@godxjp/ui 31.30.1 → 31.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,8 @@ const RangeTimeline = React.forwardRef(
35
35
  defaultLabelWidth,
36
36
  onLabelWidthChange,
37
37
  busy = false,
38
+ planLabel: timelinePlanLabel,
39
+ links,
38
40
  className,
39
41
  ...props
40
42
  }, ref) {
@@ -115,10 +117,42 @@ const RangeTimeline = React.forwardRef(
115
117
  const row = rows.find((row2) => row2.id === current.id);
116
118
  const delta = deltaAt(event.clientX);
117
119
  cancel();
120
+ if (row?.shape === "milestone") {
121
+ if (row.end !== null && delta) onRangeChange?.(row.id, "end", delta);
122
+ return;
123
+ }
118
124
  if (!row || row.start === null || row.end === null) return;
119
125
  const bounded = current.edge === "start" ? Math.min(delta, row.end - row.start) : Math.max(delta, row.start - row.end);
120
126
  if (bounded) onRangeChange?.(row.id, current.edge, bounded);
121
127
  };
128
+ const rowElements = React.useRef(/* @__PURE__ */ new Map());
129
+ const bodyRef = React.useRef(null);
130
+ const [rowCentres, setRowCentres] = React.useState(null);
131
+ const hasLinks = Boolean(links && links.length > 0);
132
+ const measureRows = React.useCallback(() => {
133
+ const body2 = bodyRef.current;
134
+ if (!body2) return;
135
+ const y = {};
136
+ rowElements.current.forEach((element, id) => {
137
+ y[id] = element.offsetTop + element.offsetHeight / 2;
138
+ });
139
+ const rtl = getComputedStyle(body2).direction === "rtl";
140
+ setRowCentres((previous) => {
141
+ if (previous && previous.rtl === rtl && Object.keys(previous.y).length === Object.keys(y).length && Object.keys(y).every((id) => previous.y[id] === y[id]))
142
+ return previous;
143
+ return { rtl, y };
144
+ });
145
+ }, []);
146
+ React.useLayoutEffect(() => {
147
+ if (hasLinks) measureRows();
148
+ });
149
+ React.useEffect(() => {
150
+ const body2 = bodyRef.current;
151
+ if (!hasLinks || !body2 || typeof ResizeObserver === "undefined") return;
152
+ const observer = new ResizeObserver(() => measureRows());
153
+ observer.observe(body2);
154
+ return () => observer.disconnect();
155
+ }, [hasLinks, measureRows]);
122
156
  const canvasStyle = {
123
157
  "--range-timeline-columns": Math.max(1, columns.length),
124
158
  "--range-timeline-units": units
@@ -196,7 +230,109 @@ const RangeTimeline = React.forwardRef(
196
230
  ] }),
197
231
  busy && /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-busy", "aria-hidden": "true" })
198
232
  ] });
199
- const body = /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", role: nested ? "list" : void 0, children: [
233
+ const fractionOf = (row, edge) => {
234
+ if (row.end === null) return null;
235
+ if (row.shape === "milestone") return Math.min(1, Math.max(0, (row.end + 0.5) / units));
236
+ if (edge === "start")
237
+ return row.start === null ? null : Math.min(1, Math.max(0, row.start / units));
238
+ return Math.min(1, Math.max(0, (row.end + 1) / units));
239
+ };
240
+ const visibleIds = new Set(visibleRows.map((row) => row.id));
241
+ const drawnLinks = hasLinks ? links.flatMap((link) => {
242
+ const from = rows.find((row) => row.id === link.from);
243
+ const to = rows.find((row) => row.id === link.to);
244
+ if (!from || !to || !visibleIds.has(from.id) || !visibleIds.has(to.id)) return [];
245
+ const type = link.type ?? "FS";
246
+ const x1 = fractionOf(from, type[0] === "F" ? "end" : "start");
247
+ const x2 = fractionOf(to, type[1] === "F" ? "end" : "start");
248
+ const y1 = rowCentres?.y[from.id];
249
+ const y2 = rowCentres?.y[to.id];
250
+ if (x1 === null || x2 === null || y1 === void 0 || y2 === void 0) return [];
251
+ return [{ link, from, to, type, x1, x2, y1, y2 }];
252
+ }) : [];
253
+ const markerBase = `${reactId.replace(/[^a-zA-Z0-9_-]/g, "")}-link-head`;
254
+ const physical = (fraction) => `${(rowCentres?.rtl ? 1 - fraction : fraction) * 100}%`;
255
+ const violatedLinks = drawnLinks.filter((drawn) => drawn.link.violated);
256
+ const linkLayer = hasLinks ? /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-links", children: [
257
+ /* @__PURE__ */ jsx("div", {}),
258
+ /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-links-track", children: [
259
+ /* @__PURE__ */ jsxs("svg", { className: "ui-range-timeline-links-svg", "aria-hidden": "true", focusable: "false", children: [
260
+ /* @__PURE__ */ jsx("defs", { children: ["normal", "violated"].map((kind) => /* @__PURE__ */ jsx(
261
+ "marker",
262
+ {
263
+ id: `${markerBase}-${kind}`,
264
+ className: "ui-range-timeline-link-head",
265
+ "data-violated": kind === "violated" ? "true" : void 0,
266
+ markerWidth: "8",
267
+ markerHeight: "8",
268
+ refX: "8",
269
+ refY: "4",
270
+ orient: "auto",
271
+ markerUnits: "userSpaceOnUse",
272
+ children: /* @__PURE__ */ jsx("path", { d: "M0,0 L8,4 L0,8 z" })
273
+ },
274
+ kind
275
+ )) }),
276
+ drawnLinks.map((drawn) => {
277
+ const middle = (drawn.x1 + drawn.x2) / 2;
278
+ const head = `url(#${markerBase}-${drawn.link.violated ? "violated" : "normal"})`;
279
+ return /* @__PURE__ */ jsxs(
280
+ "g",
281
+ {
282
+ className: "ui-range-timeline-link",
283
+ "data-link-id": drawn.link.id,
284
+ "data-violated": drawn.link.violated ? "true" : void 0,
285
+ children: [
286
+ /* @__PURE__ */ jsx("line", { x1: physical(drawn.x1), y1: drawn.y1, x2: physical(middle), y2: drawn.y1 }),
287
+ /* @__PURE__ */ jsx("line", { x1: physical(middle), y1: drawn.y1, x2: physical(middle), y2: drawn.y2 }),
288
+ /* @__PURE__ */ jsx(
289
+ "line",
290
+ {
291
+ x1: physical(middle),
292
+ y1: drawn.y2,
293
+ x2: physical(drawn.x2),
294
+ y2: drawn.y2,
295
+ markerEnd: head
296
+ }
297
+ )
298
+ ]
299
+ },
300
+ drawn.link.id
301
+ );
302
+ })
303
+ ] }),
304
+ violatedLinks.map((drawn) => {
305
+ const name = drawn.link.label ? t("rangeTimeline.dependencyViolatedWith", { label: drawn.link.label }) : t("rangeTimeline.dependencyViolated");
306
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
307
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
308
+ "span",
309
+ {
310
+ className: "ui-range-timeline-link-violation ui-focus-ring",
311
+ tabIndex: 0,
312
+ "aria-label": name,
313
+ style: {
314
+ insetInlineStart: `${drawn.x2 * 100}%`,
315
+ insetBlockStart: `${drawn.y2}px`
316
+ }
317
+ }
318
+ ) }),
319
+ /* @__PURE__ */ jsx(TooltipContent, { children: name })
320
+ ] }, drawn.link.id);
321
+ })
322
+ ] }),
323
+ violatedLinks.length > 0 && /* @__PURE__ */ jsx("ul", { className: "sr-only", children: violatedLinks.map((drawn) => /* @__PURE__ */ jsxs("li", { children: [
324
+ t("rangeTimeline.dependencyViolated"),
325
+ " ",
326
+ /* @__PURE__ */ jsx("span", { children: drawn.from.label }),
327
+ " \u2192",
328
+ " ",
329
+ /* @__PURE__ */ jsx("span", { children: drawn.to.label }),
330
+ " (",
331
+ drawn.type,
332
+ ")"
333
+ ] }, drawn.link.id)) })
334
+ ] }) : null;
335
+ const body = /* @__PURE__ */ jsxs("div", { ref: bodyRef, className: "ui-range-timeline-body", role: nested ? "list" : void 0, children: [
200
336
  (bordered || columns.some((column) => column.muted)) && // Decorative: the same unit tracks as the header columns, laid once behind every row so
201
337
  // each vertical rule runs the full body height exactly under its header column.
202
338
  /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-grid", "aria-hidden": "true", children: [
@@ -213,21 +349,114 @@ const RangeTimeline = React.forwardRef(
213
349
  ] }),
214
350
  visibleRows.map((row, index) => {
215
351
  const idBase = `${reactId}-row-${rows.indexOf(row)}`;
216
- const dated = row.start !== null && row.end !== null;
217
- const rowStart = row.start ?? 0, rowEnd = row.end ?? 0;
352
+ const milestone = row.shape === "milestone";
353
+ const finishOnly = !milestone && row.start === null && row.end !== null;
354
+ const dated = milestone ? row.end !== null : row.start !== null && row.end !== null;
355
+ const point = milestone || finishOnly;
356
+ const rowEnd = row.end ?? 0;
357
+ const rowStart = point ? rowEnd : row.start ?? 0;
218
358
  const delta = preview?.id === row.id ? preview.delta : 0;
219
- const start = Math.min(rowEnd, rowStart + (preview?.edge === "start" ? delta : 0));
220
- const end = Math.max(rowStart, rowEnd + (preview?.edge === "end" ? delta : 0));
359
+ const start = point ? rowEnd + (preview?.edge === "end" ? delta : 0) : Math.min(rowEnd, rowStart + (preview?.edge === "start" ? delta : 0));
360
+ const end = point ? start : Math.max(rowStart, rowEnd + (preview?.edge === "end" ? delta : 0));
221
361
  const left = Math.max(0, start), right = Math.min(units, end + 1);
222
- const plan = dated && row.plan && row.plan.start !== null && row.plan.end !== null ? row.plan : null;
362
+ const planStart = row.plan?.start ?? null, planEndKnown = row.plan?.end ?? null;
363
+ const plan = dated && !milestone && planStart !== null && planEndKnown !== null ? { start: planStart, end: planEndKnown } : null;
364
+ const planEnd = dated ? milestone ? planEndKnown ?? planStart : planEndKnown : null;
365
+ const planTick = dated && !milestone && !plan && (planStart !== null || planEndKnown !== null) ? planEndKnown !== null ? planEndKnown + 1 : planStart : null;
223
366
  const planLeft = plan ? Math.max(0, plan.start) : 0, planRight = plan ? Math.min(units, plan.end + 1) : 0;
224
- const overrun = plan !== null && end > plan.end;
225
- const early = plan !== null && end < plan.end;
226
- const overrunLeft = overrun ? Math.max(left, Math.min(units, plan.end + 1)) : 0;
367
+ const overrun = planEnd !== null && end > planEnd;
368
+ const early = planEnd !== null && end < planEnd;
369
+ const clampUnit = (value) => Math.min(units, Math.max(0, value));
370
+ const overrunLeft = !overrun ? 0 : milestone ? clampUnit(planEnd + 0.5) : Math.max(left, Math.min(units, planEnd + 1));
371
+ const overrunRight = milestone ? clampUnit(end + 0.5) : right;
372
+ const earlyAt = milestone ? end + 0.5 : right;
373
+ const rowPlanLabel = row.planLabel ?? timelinePlanLabel;
374
+ const overrunText = rowPlanLabel ? t("rangeTimeline.overrunVs", { plan: rowPlanLabel, n: String(end - (planEnd ?? 0)) }) : t("rangeTimeline.overrun");
375
+ const earlyText = rowPlanLabel ? t("rangeTimeline.earlyVs", { plan: rowPlanLabel, n: String((planEnd ?? 0) - end) }) : t("rangeTimeline.early");
376
+ const barStyle = (inset) => ({
377
+ ...inset,
378
+ ...row.color && {
379
+ "--range-timeline-bar-color": row.color,
380
+ "--range-timeline-bar-ink": inkOn(row.color)
381
+ }
382
+ });
383
+ const allowsEdge = (edge) => !row.cancelled && !(row.openEnd && edge === "end") && (row.editable === void 0 || row.editable === true ? true : row.editable === false ? false : row.editable[edge] !== false);
384
+ const grip = (edge) => /* @__PURE__ */ jsx(
385
+ Button,
386
+ {
387
+ variant: "ghost",
388
+ size: "icon-xs",
389
+ className: "ui-range-timeline-handle",
390
+ "data-edge": edge,
391
+ "aria-label": edge === "start" ? row.startLabel : row.endLabel,
392
+ onPointerDown: (event) => {
393
+ const width = track.current?.getBoundingClientRect().width ?? 0;
394
+ if (!width || event.button !== 0) return;
395
+ event.currentTarget.setPointerCapture(event.pointerId);
396
+ drag.current = {
397
+ id: row.id,
398
+ edge,
399
+ x: event.clientX,
400
+ width,
401
+ direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
402
+ };
403
+ },
404
+ onPointerMove: (event) => {
405
+ if (drag.current)
406
+ setPreview({
407
+ id: drag.current.id,
408
+ edge: drag.current.edge,
409
+ delta: deltaAt(event.clientX)
410
+ });
411
+ },
412
+ onPointerUp: complete,
413
+ onPointerCancel: cancel,
414
+ onLostPointerCapture: cancel,
415
+ onKeyDown: (event) => {
416
+ if (event.key === "Escape") {
417
+ cancel();
418
+ return;
419
+ }
420
+ const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
421
+ if (!step) return;
422
+ event.preventDefault();
423
+ const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
424
+ const delta2 = step * direction;
425
+ if (milestone || (edge === "start" ? rowStart + delta2 <= rowEnd : rowEnd + delta2 >= rowStart))
426
+ onRangeChange?.(row.id, edge, delta2);
427
+ },
428
+ children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
429
+ },
430
+ edge
431
+ );
432
+ const tooltipHit = row.tooltip != null ? /* @__PURE__ */ jsxs(Tooltip, { children: [
433
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
434
+ "span",
435
+ {
436
+ className: "ui-range-timeline-bar-hit ui-focus-ring",
437
+ tabIndex: 0,
438
+ "aria-labelledby": `${idBase}-label`
439
+ }
440
+ ) }),
441
+ /* @__PURE__ */ jsx(TooltipContent, { children: row.tooltip })
442
+ ] }) : null;
443
+ const stateTexts = /* @__PURE__ */ jsxs(Fragment, { children: [
444
+ row.overdue && /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.overdue") }),
445
+ row.cancelled && /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.cancelled") }),
446
+ row.openEnd && !milestone && /* @__PURE__ */ jsx("span", { className: "sr-only", children: row.openEndLabel ?? t("rangeTimeline.openEnd") })
447
+ ] });
448
+ const emphasisText = row.emphasis ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: t(
449
+ row.emphasis === "critical" ? "rangeTimeline.emphasisCritical" : "rangeTimeline.emphasisWarning"
450
+ ) }) : null;
227
451
  return /* @__PURE__ */ jsxs(
228
452
  "div",
229
453
  {
230
454
  className: "ui-range-timeline-row",
455
+ "data-emphasis": row.emphasis,
456
+ ref: links && links.length > 0 ? (element) => {
457
+ if (element) rowElements.current.set(row.id, element);
458
+ else rowElements.current.delete(row.id);
459
+ } : void 0,
231
460
  ...nested && {
232
461
  role: "listitem",
233
462
  "aria-level": depthOf(row) + 1,
@@ -263,15 +492,19 @@ const RangeTimeline = React.forwardRef(
263
492
  ]
264
493
  }
265
494
  ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ui-range-timeline-disclosure-spacer" }),
266
- /* @__PURE__ */ jsx("div", { id: `${idBase}-label`, className: "ui-range-timeline-label-content", children: row.label })
495
+ /* @__PURE__ */ jsx("div", { id: `${idBase}-label`, className: "ui-range-timeline-label-content", children: row.label }),
496
+ emphasisText
267
497
  ]
268
498
  }
269
- ) : /* @__PURE__ */ jsx(
499
+ ) : /* @__PURE__ */ jsxs(
270
500
  "div",
271
501
  {
272
502
  className: "ui-range-timeline-label",
273
503
  id: row.tooltip != null ? `${idBase}-label` : void 0,
274
- children: row.label
504
+ children: [
505
+ row.label,
506
+ emphasisText
507
+ ]
275
508
  }
276
509
  ),
277
510
  /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-track", children: [
@@ -283,14 +516,22 @@ const RangeTimeline = React.forwardRef(
283
516
  style: { insetInlineStart: `${(today + 0.5) / units * 100}%` }
284
517
  }
285
518
  ),
286
- !dated && /* @__PURE__ */ jsx("span", { className: "ui-range-timeline-outside", "data-direction": "none", children: /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.noDates") }) }),
287
- dated && right <= left && (end < 0 ? /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "before", children: [
519
+ !dated && !finishOnly && row.emptyHint !== false && /* @__PURE__ */ jsx("span", { className: "ui-range-timeline-outside", "data-direction": "none", children: /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: row.emptyHint ?? t("rangeTimeline.noDates") }) }),
520
+ (dated || finishOnly) && right <= left && (end < 0 ? /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "before", children: [
288
521
  /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "ui-range-timeline-outside-icon" }),
289
522
  /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideBefore") })
290
523
  ] }) : /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "after", children: [
291
524
  /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideAfter") }),
292
525
  /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "ui-range-timeline-outside-icon" })
293
526
  ] })),
527
+ finishOnly && right > left && /* @__PURE__ */ jsx(
528
+ "span",
529
+ {
530
+ className: "ui-range-timeline-finish",
531
+ style: barStyle({ insetInlineStart: `${right / units * 100}%` }),
532
+ children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: row.startUnknownLabel ?? t("rangeTimeline.startUnknown") })
533
+ }
534
+ ),
294
535
  plan && planRight > planLeft && /* @__PURE__ */ jsx(
295
536
  "span",
296
537
  {
@@ -302,21 +543,37 @@ const RangeTimeline = React.forwardRef(
302
543
  }
303
544
  }
304
545
  ),
305
- overrun && right > overrunLeft && /* @__PURE__ */ jsxs(
546
+ planTick !== null && planTick >= 0 && planTick <= units && /* @__PURE__ */ jsx(
547
+ "span",
548
+ {
549
+ "aria-hidden": "true",
550
+ className: "ui-range-timeline-plan-tick",
551
+ style: { insetInlineStart: `${planTick / units * 100}%` }
552
+ }
553
+ ),
554
+ milestone && planEnd !== null && planEnd >= 0 && planEnd < units && /* @__PURE__ */ jsx(
555
+ "span",
556
+ {
557
+ "aria-hidden": "true",
558
+ className: "ui-range-timeline-plan-diamond",
559
+ style: { insetInlineStart: `${(planEnd + 0.5) / units * 100}%` }
560
+ }
561
+ ),
562
+ overrun && overrunRight > overrunLeft && /* @__PURE__ */ jsxs(
306
563
  "span",
307
564
  {
308
565
  className: "ui-range-timeline-overrun",
309
566
  style: {
310
567
  insetInlineStart: `${overrunLeft / units * 100}%`,
311
- inlineSize: `${(right - overrunLeft) / units * 100}%`
568
+ inlineSize: `${(overrunRight - overrunLeft) / units * 100}%`
312
569
  },
313
570
  children: [
314
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.overrun") }),
315
- row.varianceLabel !== false && /* @__PURE__ */ jsx("span", { className: "ui-range-timeline-variance", children: row.varianceLabel ?? t("rangeTimeline.lateBy", { n: String(end - plan.end) }) })
571
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: overrunText }),
572
+ row.varianceLabel !== false && /* @__PURE__ */ jsx("span", { className: "ui-range-timeline-variance", children: row.varianceLabel ?? t("rangeTimeline.lateBy", { n: String(end - planEnd) }) })
316
573
  ]
317
574
  }
318
575
  ),
319
- dated && !plan && row.planNote != null && right > left && /* @__PURE__ */ jsx(
576
+ dated && planStart === null && planEndKnown === null && row.planNote != null && right > left && /* @__PURE__ */ jsx(
320
577
  "span",
321
578
  {
322
579
  className: "ui-range-timeline-plan-note",
@@ -324,93 +581,55 @@ const RangeTimeline = React.forwardRef(
324
581
  children: row.planNote
325
582
  }
326
583
  ),
327
- early && right > left && right <= units && /* @__PURE__ */ jsx(
584
+ early && right > left && earlyAt <= units && /* @__PURE__ */ jsx(
328
585
  "span",
329
586
  {
330
587
  className: "ui-range-timeline-early",
331
- style: { insetInlineStart: `${right / units * 100}%` },
332
- children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.early") })
588
+ style: { insetInlineStart: `${earlyAt / units * 100}%` },
589
+ children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: earlyText })
333
590
  }
334
591
  ),
335
- dated && right > left && /* @__PURE__ */ jsxs(
592
+ early && right > left && earlyAt <= units && row.earlyLabel !== false && /* @__PURE__ */ jsx(
593
+ "span",
594
+ {
595
+ className: "ui-range-timeline-early-label",
596
+ style: { insetInlineStart: `${earlyAt / units * 100}%` },
597
+ children: row.earlyLabel ?? t("rangeTimeline.earlyBy", { n: String(planEnd - end) })
598
+ }
599
+ ),
600
+ milestone && dated && right > left && /* @__PURE__ */ jsxs(
601
+ "span",
602
+ {
603
+ className: "ui-range-timeline-milestone",
604
+ "data-muted": row.muted ? "true" : void 0,
605
+ "data-overdue": row.overdue ? "true" : void 0,
606
+ "data-cancelled": row.cancelled ? "true" : void 0,
607
+ style: barStyle({ insetInlineStart: `${(end + 0.5) / units * 100}%` }),
608
+ children: [
609
+ tooltipHit,
610
+ stateTexts,
611
+ onRangeChange && allowsEdge("end") && grip("end")
612
+ ]
613
+ }
614
+ ),
615
+ !milestone && dated && right > left && /* @__PURE__ */ jsxs(
336
616
  "div",
337
617
  {
338
618
  className: "ui-range-timeline-bar",
339
619
  "data-muted": row.muted ? "true" : void 0,
340
620
  "data-overdue": row.overdue ? "true" : void 0,
341
- style: {
621
+ "data-cancelled": row.cancelled ? "true" : void 0,
622
+ "data-open-end": row.openEnd ? "true" : void 0,
623
+ style: barStyle({
342
624
  insetInlineStart: `${left / units * 100}%`,
343
- inlineSize: `${(right - left) / units * 100}%`,
344
- ...row.color && {
345
- "--range-timeline-bar-color": row.color,
346
- "--range-timeline-bar-ink": inkOn(row.color)
347
- }
348
- },
625
+ inlineSize: `${(right - left) / units * 100}%`
626
+ }),
349
627
  children: [
350
- row.tooltip != null && /* @__PURE__ */ jsxs(Tooltip, { children: [
351
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
352
- "span",
353
- {
354
- className: "ui-range-timeline-bar-hit ui-focus-ring",
355
- tabIndex: 0,
356
- "aria-labelledby": `${idBase}-label`
357
- }
358
- ) }),
359
- /* @__PURE__ */ jsx(TooltipContent, { children: row.tooltip })
360
- ] }),
361
- row.overdue && /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("rangeTimeline.overdue") }),
628
+ tooltipHit,
629
+ stateTexts,
362
630
  onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
363
631
  (edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
364
- ).filter(
365
- (edge) => row.editable === void 0 || row.editable === true ? true : row.editable === false ? false : row.editable[edge] !== false
366
- ).map((edge) => /* @__PURE__ */ jsx(
367
- Button,
368
- {
369
- variant: "ghost",
370
- size: "icon-xs",
371
- className: "ui-range-timeline-handle",
372
- "data-edge": edge,
373
- "aria-label": edge === "start" ? row.startLabel : row.endLabel,
374
- onPointerDown: (event) => {
375
- const width = track.current?.getBoundingClientRect().width ?? 0;
376
- if (!width || event.button !== 0) return;
377
- event.currentTarget.setPointerCapture(event.pointerId);
378
- drag.current = {
379
- id: row.id,
380
- edge,
381
- x: event.clientX,
382
- width,
383
- direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
384
- };
385
- },
386
- onPointerMove: (event) => {
387
- if (drag.current)
388
- setPreview({
389
- id: drag.current.id,
390
- edge: drag.current.edge,
391
- delta: deltaAt(event.clientX)
392
- });
393
- },
394
- onPointerUp: complete,
395
- onPointerCancel: cancel,
396
- onLostPointerCapture: cancel,
397
- onKeyDown: (event) => {
398
- if (event.key === "Escape") {
399
- cancel();
400
- return;
401
- }
402
- const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
403
- if (!step) return;
404
- event.preventDefault();
405
- const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
406
- const delta2 = step * direction;
407
- if (edge === "start" ? rowStart + delta2 <= rowEnd : rowEnd + delta2 >= rowStart)
408
- onRangeChange(row.id, edge, delta2);
409
- },
410
- children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
411
- },
412
- edge
413
- ))
632
+ ).filter(allowsEdge).map(grip)
414
633
  ]
415
634
  }
416
635
  )
@@ -419,7 +638,8 @@ const RangeTimeline = React.forwardRef(
419
638
  },
420
639
  row.id
421
640
  );
422
- })
641
+ }),
642
+ linkLayer
423
643
  ] });
424
644
  const sectionProps = {
425
645
  ...props,
@@ -20,6 +20,7 @@ import {
20
20
  } from "../feedback/dialog.js";
21
21
  import { Command, CommandGroup } from "./command.js";
22
22
  import { Input } from "./input.js";
23
+ import { isImeComposing } from "../../lib/ime.js";
23
24
  import { Select } from "./select.js";
24
25
  function selectLoadOptionsFor(loadOptions) {
25
26
  if (!loadOptions) return void 0;
@@ -223,6 +224,11 @@ const InlinePicker = React.forwardRef(function InlinePicker2({
223
224
  setOpenSuggest(true);
224
225
  },
225
226
  onFocus: () => setOpenSuggest(true),
227
+ onKeyDown: (event) => {
228
+ if (event.key !== "Enter" || isImeComposing(event)) return;
229
+ event.preventDefault();
230
+ if (!disabled) setDialogQuery(query);
231
+ },
226
232
  className: "ui-record-picker-inline-input",
227
233
  id,
228
234
  "data-field": fieldName,
@@ -39,6 +39,8 @@ const Segmented = React.forwardRef(function Segmented2({
39
39
  name,
40
40
  id,
41
41
  className,
42
+ "aria-label": ariaLabel,
43
+ "aria-labelledby": ariaLabelledBy,
42
44
  ...props
43
45
  }, ref) {
44
46
  return /* @__PURE__ */ jsx(
@@ -56,6 +58,8 @@ const Segmented = React.forwardRef(function Segmented2({
56
58
  onChange: onValueChange,
57
59
  isDisabled: disabled,
58
60
  name,
61
+ "aria-labelledby": ariaLabelledBy,
62
+ "aria-label": ariaLabelledBy ? void 0 : ariaLabel,
59
63
  ...props,
60
64
  children: options.map((option) => /* @__PURE__ */ jsxs(
61
65
  AriaRadio,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
3
- "version": "31.30.1",
3
+ "version": "31.31.1",
4
4
  "targetSize": {
5
5
  "standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
6
6
  "min": 24,
@@ -771,7 +771,17 @@
771
771
  "overdue": "Overdue",
772
772
  "overrun": "Over the plan",
773
773
  "early": "Ahead of the plan",
774
- "lateBy": "+{n}d"
774
+ "lateBy": "+{n}d",
775
+ "startUnknown": "Start unknown",
776
+ "openEnd": "Completion not recorded",
777
+ "cancelled": "Cancelled",
778
+ "overrunVs": "{n}d behind {plan}",
779
+ "earlyVs": "{n}d ahead of {plan}",
780
+ "earlyBy": "-{n}d",
781
+ "dependencyViolated": "Dependency violated",
782
+ "dependencyViolatedWith": "Dependency violated: {label}",
783
+ "emphasisWarning": "At risk",
784
+ "emphasisCritical": "Critical path"
775
785
  },
776
786
  "chat": {
777
787
  "bubble": {
@@ -746,7 +746,17 @@
746
746
  "overdue": "期限超過",
747
747
  "overrun": "予定超過",
748
748
  "early": "予定より早く完了",
749
- "lateBy": "+{n}日"
749
+ "lateBy": "+{n}日",
750
+ "startUnknown": "開始日不明",
751
+ "openEnd": "完了未記録",
752
+ "cancelled": "中止",
753
+ "overrunVs": "{plan}より{n}日遅れ",
754
+ "earlyVs": "{plan}より{n}日早い",
755
+ "earlyBy": "-{n}日",
756
+ "dependencyViolated": "依存関係の違反",
757
+ "dependencyViolatedWith": "依存関係の違反:{label}",
758
+ "emphasisWarning": "要注意",
759
+ "emphasisCritical": "クリティカルパス"
750
760
  },
751
761
  "chat": {
752
762
  "bubble": {
@@ -747,7 +747,17 @@
747
747
  "overdue": "Quá hạn",
748
748
  "overrun": "Vượt kế hoạch",
749
749
  "early": "Sớm hơn kế hoạch",
750
- "lateBy": "+{n} ngày"
750
+ "lateBy": "+{n} ngày",
751
+ "startUnknown": "Chưa rõ ngày bắt đầu",
752
+ "openEnd": "Chưa ghi nhận hoàn thành",
753
+ "cancelled": "Đã hủy",
754
+ "overrunVs": "Chậm {n} ngày so với {plan}",
755
+ "earlyVs": "Sớm {n} ngày so với {plan}",
756
+ "earlyBy": "-{n} ngày",
757
+ "dependencyViolated": "Vi phạm phụ thuộc",
758
+ "dependencyViolatedWith": "Vi phạm phụ thuộc: {label}",
759
+ "emphasisWarning": "Có rủi ro",
760
+ "emphasisCritical": "Đường găng"
751
761
  },
752
762
  "chat": {
753
763
  "bubble": {