@thebuoyant-tsdev/mui-ts-library 3.15.0 → 3.16.0

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.de.md CHANGED
@@ -40,6 +40,7 @@ Eine typsichere React-Komponentenbibliothek auf Basis von **TypeScript** und **M
40
40
  | [`RadialTreeChart`](#radialtreechart) | Org-Charts und Taxonomien als radialer Baum, mit Drill-Down | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-radialtreechart--default) · [Docs](user-manuals/RadialTreeChart.de.md) |
41
41
  | [`CirclePackingChart`](#circlepackingchart) | Verschachtelte Kreise mit animiertem Zoom — Speicher und Hierarchie auf einen Blick | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-circlepackingchart--default) · [Docs](user-manuals/CirclePackingChart.de.md) |
42
42
  | [`HorizontalTreeChart`](#horizontaltreechart) | Entscheidungsbäume und Hierarchien in 4 Orientierungen (LR/RL/TB/BT) | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-horizontaltreechart--default) · [Docs](user-manuals/HorizontalTreeChart.de.md) |
43
+ | [`RadialStackedBarChart`](#radialstackedbarchart) | Mehrreihige gestapelte Balken in polarem Layout — Kategorien über Segmente vergleichen | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-radialstackedbarchart--default) · [Docs](user-manuals/RadialStackedBarChart.de.md) |
43
44
 
44
45
  Alle Charts teilen sich Ctrl / Cmd ⌘+Scroll-Zoom und vollständige MUI-Theme-Integration (Dark Mode inklusive).
45
46
 
@@ -375,6 +376,43 @@ const data: HorizontalTreeData = {
375
376
 
376
377
  ---
377
378
 
379
+ ### RadialStackedBarChart
380
+
381
+ Mehrreihiges gestapeltes Balkendiagramm in polarem Layout. Jedes Balkensegment repräsentiert einen Datenpunkt, jede Bogen-Ebene eine Datenreihe — ideal für Quartalsvergleiche, Budgetaufschlüsselungen oder mehrere Kategorien über eine Menge von Einträgen. Konzentrische Gitterringe geben visuelle Skala; eine automatisch zentrierte Legende ist integriert. `Ctrl / Cmd ⌘+Scroll` zoomt den Chart.
382
+
383
+ ```tsx
384
+ import { RadialStackedBarChart } from '@thebuoyant-tsdev/mui-ts-library';
385
+ import type {
386
+ RadialStackedBarData,
387
+ RadialStackedBarSeries,
388
+ } from '@thebuoyant-tsdev/mui-ts-library';
389
+
390
+ const keys: RadialStackedBarSeries[] = [
391
+ { key: 'q1', label: 'Q1' },
392
+ { key: 'q2', label: 'Q2' },
393
+ { key: 'q3', label: 'Q3' },
394
+ { key: 'q4', label: 'Q4' },
395
+ ];
396
+
397
+ const data: RadialStackedBarData[] = [
398
+ { id: 'berlin', label: 'Berlin', values: { q1: 120, q2: 145, q3: 98, q4: 175 } },
399
+ { id: 'hamburg', label: 'Hamburg', values: { q1: 95, q2: 110, q3: 130, q4: 88 } },
400
+ { id: 'munich', label: 'Munich', values: { q1: 200, q2: 185, q3: 210, q4: 230 } },
401
+ ];
402
+
403
+ <RadialStackedBarChart
404
+ data={data}
405
+ keys={keys}
406
+ size={480}
407
+ sortBy="value"
408
+ onBarClick={(info) => console.log(info.label, info.seriesKey, info.value)}
409
+ />
410
+ ```
411
+
412
+ → [Vollständige Dokumentation](user-manuals/RadialStackedBarChart.de.md)
413
+
414
+ ---
415
+
378
416
  ## TypeScript
379
417
 
380
418
  Alle Typen und Defaults werden direkt exportiert — kein separates `@types/...`-Paket nötig.
@@ -413,6 +451,9 @@ import type {
413
451
 
414
452
  // HorizontalTreeChart
415
453
  HorizontalTreeData, HorizontalTreeNodeInfo, HorizontalTreeOrientation,
454
+
455
+ // RadialStackedBarChart
456
+ RadialStackedBarData, RadialStackedBarSeries, RadialStackedBarClickInfo,
416
457
  } from '@thebuoyant-tsdev/mui-ts-library';
417
458
  ```
418
459
 
@@ -434,6 +475,13 @@ Dieses Projekt folgt [Semantic Versioning](https://semver.org/). In der Praxis b
434
475
 
435
476
  ## Changelog
436
477
 
478
+ ### [3.16.0] — 2026-07-03
479
+
480
+ **Hinzugefügt**
481
+ - `GanttChart`: Fortschritts-Slider im eingebauten Hinzufügen-/Bearbeiten-Dialog — `GanttTask.progress` (0–100 %) ist jetzt ohne Maus bearbeitbar, schließt eine Accessibility-Lücke für Tastatur-Nutzer. Slider wird im Bearbeiten-Modus aus bestehenden Task-Daten vorbelegt; setzt auf 0 zurück wenn Meilenstein aktiviert wird. Neuer optionaler Übersetzungsschlüssel `dialogFieldProgress`. Siehe [Vollständiger Changelog](https://github.com/thebuoyant/mui-ts-library/blob/main/CHANGELOG.md) für Details.
482
+
483
+ ---
484
+
437
485
  ### [3.15.0] — 2026-07-03
438
486
 
439
487
  **Hinzugefügt**
package/README.md CHANGED
@@ -40,6 +40,7 @@ A type-safe React component library built on **TypeScript** and **MUI (Material
40
40
  | [`RadialTreeChart`](#radialtreechart) | Org charts and taxonomies as a radial tree, with drill-down | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-radialtreechart--default) · [Docs](user-manuals/RadialTreeChart.md) |
41
41
  | [`CirclePackingChart`](#circlepackingchart) | Nested circles with animated zoom — storage and hierarchy at a glance | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-circlepackingchart--default) · [Docs](user-manuals/CirclePackingChart.md) |
42
42
  | [`HorizontalTreeChart`](#horizontaltreechart) | Decision trees and hierarchies in 4 orientations (LR/RL/TB/BT) | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-horizontaltreechart--default) · [Docs](user-manuals/HorizontalTreeChart.md) |
43
+ | [`RadialStackedBarChart`](#radialstackedbarchart) | Multi-series stacked bars in a radial layout — compare categories across segments | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-radialstackedbarchart--default) · [Docs](user-manuals/RadialStackedBarChart.md) |
43
44
 
44
45
  All charts share Ctrl / Cmd ⌘+Scroll zoom and full MUI theme integration (dark mode included).
45
46
 
@@ -375,6 +376,43 @@ const data: HorizontalTreeData = {
375
376
 
376
377
  ---
377
378
 
379
+ ### RadialStackedBarChart
380
+
381
+ Multi-series stacked bar chart in a polar (radial) layout. Each bar segment represents one data point, each arc layer represents one series — ideal for comparing quarterly figures, budget breakdowns, or any multi-category totals across a set of items. Concentric grid rings give a visual scale; an auto-centered legend is built in. `Ctrl / Cmd ⌘+Scroll` zooms the chart.
382
+
383
+ ```tsx
384
+ import { RadialStackedBarChart } from '@thebuoyant-tsdev/mui-ts-library';
385
+ import type {
386
+ RadialStackedBarData,
387
+ RadialStackedBarSeries,
388
+ } from '@thebuoyant-tsdev/mui-ts-library';
389
+
390
+ const keys: RadialStackedBarSeries[] = [
391
+ { key: 'q1', label: 'Q1' },
392
+ { key: 'q2', label: 'Q2' },
393
+ { key: 'q3', label: 'Q3' },
394
+ { key: 'q4', label: 'Q4' },
395
+ ];
396
+
397
+ const data: RadialStackedBarData[] = [
398
+ { id: 'berlin', label: 'Berlin', values: { q1: 120, q2: 145, q3: 98, q4: 175 } },
399
+ { id: 'hamburg', label: 'Hamburg', values: { q1: 95, q2: 110, q3: 130, q4: 88 } },
400
+ { id: 'munich', label: 'Munich', values: { q1: 200, q2: 185, q3: 210, q4: 230 } },
401
+ ];
402
+
403
+ <RadialStackedBarChart
404
+ data={data}
405
+ keys={keys}
406
+ size={480}
407
+ sortBy="value"
408
+ onBarClick={(info) => console.log(info.label, info.seriesKey, info.value)}
409
+ />
410
+ ```
411
+
412
+ → [Full documentation](user-manuals/RadialStackedBarChart.md)
413
+
414
+ ---
415
+
378
416
  ## TypeScript
379
417
 
380
418
  All types and defaults are exported directly — no separate `@types/...` package needed.
@@ -413,6 +451,9 @@ import type {
413
451
 
414
452
  // HorizontalTreeChart
415
453
  HorizontalTreeData, HorizontalTreeNodeInfo, HorizontalTreeOrientation,
454
+
455
+ // RadialStackedBarChart
456
+ RadialStackedBarData, RadialStackedBarSeries, RadialStackedBarClickInfo,
416
457
  } from '@thebuoyant-tsdev/mui-ts-library';
417
458
  ```
418
459
 
@@ -434,6 +475,13 @@ This project follows [Semantic Versioning](https://semver.org/). In practice:
434
475
 
435
476
  ## Changelog
436
477
 
478
+ ### [3.16.0] — 2026-07-03
479
+
480
+ **Added**
481
+ - `GanttChart`: progress slider in the built-in Add/Edit task dialog — `GanttTask.progress` (0–100 %) is now editable without a mouse, closing an accessibility gap for keyboard users. Slider pre-fills from existing task data in edit mode; resets to 0 when milestone is toggled on. New optional translation key `dialogFieldProgress`. See [Full Changelog](https://github.com/thebuoyant/mui-ts-library/blob/main/CHANGELOG.md) for details.
482
+
483
+ ---
484
+
437
485
  ### [3.15.0] — 2026-07-03
438
486
 
439
487
  **Added**
@@ -52,6 +52,8 @@ export type GanttTranslations = {
52
52
  dialogDeleteConfirm: string;
53
53
  dialogFieldDependencies: string;
54
54
  dialogFieldDependenciesNone: string;
55
+ /** Label for the progress slider in the task dialog (0–100 %) @since 3.16.0 */
56
+ dialogFieldProgress?: string;
55
57
  columnActions: string;
56
58
  /** Header label for the Assignee column — shown when showAssigneeColumn=true @since 2.7.0 */
57
59
  columnAssignee?: string;
@@ -32,6 +32,7 @@ var e = {
32
32
  dialogDeleteConfirm: "Soll die Aufgabe \"{name}\" wirklich gelöscht werden?",
33
33
  dialogFieldDependencies: "Vorgänger",
34
34
  dialogFieldDependenciesNone: "— Keine —",
35
+ dialogFieldProgress: "Fortschritt (%)",
35
36
  scrollToTodayTooltip: "Zum heutigen Tag",
36
37
  expandAllTooltip: "Alle aufklappen",
37
38
  collapseAllTooltip: "Alle zuklappen",
@@ -1,24 +1,24 @@
1
1
  import { getDependencyCycleCandidates as e } from "./util/gantt-chart.util.js";
2
2
  import { useGanttChartStore as t, useGanttTranslations as n } from "./GanttChart.js";
3
3
  import { useEffect as r, useMemo as i, useRef as a, useState as o } from "react";
4
- import { Box as s, Button as c, Checkbox as l, Dialog as u, DialogActions as d, DialogContent as f, DialogTitle as p, FormControl as m, FormControlLabel as h, InputLabel as g, MenuItem as _, Select as v, TextField as y, Tooltip as b, Typography as x } from "@mui/material";
5
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
4
+ import { Box as s, Button as c, Checkbox as l, Dialog as u, DialogActions as d, DialogContent as f, DialogTitle as p, FormControl as m, FormControlLabel as h, InputLabel as g, MenuItem as _, Select as v, Slider as y, TextField as b, Tooltip as x, Typography as S } from "@mui/material";
5
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
6
6
  //#region src/components/gantt-chart/GanttTaskDialog.tsx
7
- function w(e) {
7
+ function T(e) {
8
8
  return e.toISOString().slice(0, 10);
9
9
  }
10
- function T(e, t, n) {
10
+ function E(e, t, n) {
11
11
  return e < t ? t : e > n ? n : e;
12
12
  }
13
- function E(e) {
14
- return e.flatMap((e) => [e, ...E(e.children)]);
13
+ function D(e) {
14
+ return e.flatMap((e) => [e, ...D(e.children)]);
15
15
  }
16
- function D({ label: e }) {
16
+ function O({ label: e }) {
17
17
  let t = a(null), [n, r] = o(!1);
18
- return /* @__PURE__ */ S(b, {
18
+ return /* @__PURE__ */ C(x, {
19
19
  title: e,
20
20
  disableHoverListener: !n,
21
- children: /* @__PURE__ */ S(x, {
21
+ children: /* @__PURE__ */ C(S, {
22
22
  ref: t,
23
23
  component: "span",
24
24
  variant: "body2",
@@ -36,106 +36,111 @@ function D({ label: e }) {
36
36
  })
37
37
  });
38
38
  }
39
- function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, onClose: j }) {
40
- let M = n(), N = t((e) => e.taskTree), P = t((e) => e.timelineRange), F = i(() => E(N), [N]), I = i(() => {
41
- if (b === "add" || !O) return /* @__PURE__ */ new Set();
42
- let e = (t) => [t.id, ...t.children.flatMap(e)], t = F.find((e) => e.id === O.id);
43
- return new Set(t ? e(t) : [O.id]);
39
+ function k({ open: a, mode: x, initialTask: k, defaultParentId: A, onSave: j, onClose: M }) {
40
+ let N = n(), P = t((e) => e.taskTree), F = t((e) => e.timelineRange), I = i(() => D(P), [P]), L = i(() => {
41
+ if (x === "add" || !k) return /* @__PURE__ */ new Set();
42
+ let e = (t) => [t.id, ...t.children.flatMap(e)], t = I.find((e) => e.id === k.id);
43
+ return new Set(t ? e(t) : [k.id]);
44
44
  }, [
45
- b,
46
- O,
47
- F
48
- ]), L = F.filter((e) => !I.has(e.id)), R = i(() => b === "add" || !O ? /* @__PURE__ */ new Set() : e(F, O.id), [
49
- b,
50
- O,
51
- F
52
- ]), z = L.filter((e) => !R.has(e.id)), B = w(T(/* @__PURE__ */ new Date(), P.start, P.end)), [V, H] = o({
45
+ x,
46
+ k,
47
+ I
48
+ ]), R = I.filter((e) => !L.has(e.id)), z = i(() => x === "add" || !k ? /* @__PURE__ */ new Set() : e(I, k.id), [
49
+ x,
50
+ k,
51
+ I
52
+ ]), B = R.filter((e) => !z.has(e.id)), V = T(E(/* @__PURE__ */ new Date(), F.start, F.end)), [H, U] = o({
53
53
  name: "",
54
- startDate: B,
55
- endDate: B,
54
+ startDate: V,
55
+ endDate: V,
56
56
  status: "planned",
57
57
  isMilestone: !1,
58
+ progress: 0,
58
59
  parentId: "",
59
60
  dependencies: [],
60
61
  assignee: ""
61
62
  });
62
63
  r(() => {
63
64
  if (!a) return;
64
- let e = w(T(/* @__PURE__ */ new Date(), P.start, P.end));
65
- H(b === "edit" && O ? {
66
- name: O.name,
67
- startDate: w(O.startDate),
68
- endDate: w(O.endDate),
69
- status: O.status,
70
- isMilestone: O.isMilestone ?? !1,
71
- parentId: O.parentId ?? "",
72
- dependencies: O.dependencies ?? [],
73
- assignee: O.assignee ?? ""
65
+ let e = T(E(/* @__PURE__ */ new Date(), F.start, F.end));
66
+ U(x === "edit" && k ? {
67
+ name: k.name,
68
+ startDate: T(k.startDate),
69
+ endDate: T(k.endDate),
70
+ status: k.status,
71
+ isMilestone: k.isMilestone ?? !1,
72
+ progress: k.progress ?? 0,
73
+ parentId: k.parentId ?? "",
74
+ dependencies: k.dependencies ?? [],
75
+ assignee: k.assignee ?? ""
74
76
  } : {
75
77
  name: "",
76
78
  startDate: e,
77
79
  endDate: e,
78
80
  status: "planned",
79
81
  isMilestone: !1,
80
- parentId: k ?? "",
82
+ progress: 0,
83
+ parentId: A ?? "",
81
84
  dependencies: [],
82
85
  assignee: ""
83
86
  });
84
87
  }, [
85
88
  a,
86
- b,
87
- O,
89
+ x,
88
90
  k,
89
- P
91
+ A,
92
+ F
90
93
  ]);
91
- let U = (e) => {
92
- H((t) => ({
94
+ let W = (e) => {
95
+ U((t) => ({
93
96
  ...t,
94
97
  startDate: e,
95
98
  endDate: t.isMilestone || t.endDate < e ? e : t.endDate
96
99
  }));
97
- }, W = (e) => {
98
- H((t) => ({
100
+ }, G = (e) => {
101
+ U((t) => ({
99
102
  ...t,
100
103
  endDate: e < t.startDate ? t.startDate : e
101
104
  }));
102
- }, G = (e) => {
103
- H((t) => ({
105
+ }, K = (e) => {
106
+ U((t) => ({
104
107
  ...t,
105
108
  isMilestone: e,
106
- endDate: e ? t.startDate : t.endDate
109
+ endDate: e ? t.startDate : t.endDate,
110
+ progress: e ? 0 : t.progress
107
111
  }));
108
- }, K = V.name.trim() !== "" && V.startDate !== "" && V.endDate !== "" && V.endDate >= V.startDate, q = () => {
109
- K && A({
110
- name: V.name.trim(),
111
- startDate: new Date(V.startDate),
112
- endDate: new Date(V.endDate),
113
- status: V.status,
114
- isMilestone: V.isMilestone || void 0,
115
- parentId: V.parentId || void 0,
116
- dependencies: V.dependencies.length > 0 ? V.dependencies : void 0,
117
- assignee: V.assignee.trim() || void 0
112
+ }, q = H.name.trim() !== "" && H.startDate !== "" && H.endDate !== "" && H.endDate >= H.startDate, J = () => {
113
+ q && j({
114
+ name: H.name.trim(),
115
+ startDate: new Date(H.startDate),
116
+ endDate: new Date(H.endDate),
117
+ status: H.status,
118
+ isMilestone: H.isMilestone || void 0,
119
+ progress: H.progress > 0 ? H.progress : void 0,
120
+ parentId: H.parentId || void 0,
121
+ dependencies: H.dependencies.length > 0 ? H.dependencies : void 0,
122
+ assignee: H.assignee.trim() || void 0
118
123
  });
119
- }, J = [
124
+ }, Y = [
120
125
  "planned",
121
126
  "in-progress",
122
127
  "done",
123
128
  "blocked"
124
- ], Y = {
125
- planned: M.statusPlanned,
126
- "in-progress": M.statusInProgress,
127
- done: M.statusDone,
128
- blocked: M.statusBlocked
129
+ ], X = {
130
+ planned: N.statusPlanned,
131
+ "in-progress": N.statusInProgress,
132
+ done: N.statusDone,
133
+ blocked: N.statusBlocked
129
134
  };
130
- return /* @__PURE__ */ C(u, {
135
+ return /* @__PURE__ */ w(u, {
131
136
  open: a,
132
- onClose: j,
137
+ onClose: M,
133
138
  maxWidth: "xs",
134
139
  fullWidth: !0,
135
140
  "data-testid": "gantt-task-dialog",
136
141
  children: [
137
- /* @__PURE__ */ S(p, { children: b === "add" ? M.dialogAddTitle : M.dialogEditTitle }),
138
- /* @__PURE__ */ C(f, {
142
+ /* @__PURE__ */ C(p, { children: x === "add" ? N.dialogAddTitle : N.dialogEditTitle }),
143
+ /* @__PURE__ */ w(f, {
139
144
  sx: {
140
145
  display: "flex",
141
146
  flexDirection: "column",
@@ -143,10 +148,10 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
143
148
  pt: "16px !important"
144
149
  },
145
150
  children: [
146
- /* @__PURE__ */ S(y, {
147
- label: M.dialogFieldName,
148
- value: V.name,
149
- onChange: (e) => H((t) => ({
151
+ /* @__PURE__ */ C(b, {
152
+ label: N.dialogFieldName,
153
+ value: H.name,
154
+ onChange: (e) => U((t) => ({
150
155
  ...t,
151
156
  name: e.target.value
152
157
  })),
@@ -156,10 +161,10 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
156
161
  autoFocus: !0,
157
162
  slotProps: { htmlInput: { "data-testid": "gantt-dialog-field-name" } }
158
163
  }),
159
- /* @__PURE__ */ S(y, {
160
- label: M.columnAssignee,
161
- value: V.assignee,
162
- onChange: (e) => H((t) => ({
164
+ /* @__PURE__ */ C(b, {
165
+ label: N.columnAssignee,
166
+ value: H.assignee,
167
+ onChange: (e) => U((t) => ({
163
168
  ...t,
164
169
  assignee: e.target.value
165
170
  })),
@@ -168,11 +173,11 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
168
173
  placeholder: "e.g. Jane Smith",
169
174
  slotProps: { htmlInput: { "data-testid": "gantt-dialog-field-assignee" } }
170
175
  }),
171
- /* @__PURE__ */ S(y, {
172
- label: M.dialogFieldStartDate,
176
+ /* @__PURE__ */ C(b, {
177
+ label: N.dialogFieldStartDate,
173
178
  type: "date",
174
- value: V.startDate,
175
- onChange: (e) => U(e.target.value),
179
+ value: H.startDate,
180
+ onChange: (e) => W(e.target.value),
176
181
  required: !0,
177
182
  fullWidth: !0,
178
183
  size: "small",
@@ -181,68 +186,109 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
181
186
  htmlInput: { "data-testid": "gantt-dialog-field-start" }
182
187
  }
183
188
  }),
184
- /* @__PURE__ */ S(y, {
185
- label: M.dialogFieldEndDate,
189
+ /* @__PURE__ */ C(b, {
190
+ label: N.dialogFieldEndDate,
186
191
  type: "date",
187
- value: V.endDate,
188
- onChange: (e) => W(e.target.value),
192
+ value: H.endDate,
193
+ onChange: (e) => G(e.target.value),
189
194
  required: !0,
190
195
  fullWidth: !0,
191
196
  size: "small",
192
- disabled: V.isMilestone,
197
+ disabled: H.isMilestone,
193
198
  slotProps: {
194
199
  inputLabel: { shrink: !0 },
195
200
  htmlInput: {
196
201
  "data-testid": "gantt-dialog-field-end",
197
- min: V.startDate
202
+ min: H.startDate
198
203
  }
199
204
  }
200
205
  }),
201
- /* @__PURE__ */ C(m, {
206
+ /* @__PURE__ */ w(m, {
202
207
  size: "small",
203
208
  fullWidth: !0,
204
- children: [/* @__PURE__ */ S(g, { children: M.dialogFieldStatus }), /* @__PURE__ */ S(v, {
205
- value: V.status,
206
- label: M.dialogFieldStatus,
207
- onChange: (e) => H((t) => ({
209
+ children: [/* @__PURE__ */ C(g, { children: N.dialogFieldStatus }), /* @__PURE__ */ C(v, {
210
+ value: H.status,
211
+ label: N.dialogFieldStatus,
212
+ onChange: (e) => U((t) => ({
208
213
  ...t,
209
214
  status: e.target.value
210
215
  })),
211
216
  inputProps: { "data-testid": "gantt-dialog-field-status" },
212
- children: J.map((e) => /* @__PURE__ */ S(_, {
217
+ children: Y.map((e) => /* @__PURE__ */ C(_, {
213
218
  value: e,
214
- children: Y[e]
219
+ children: X[e]
215
220
  }, e))
216
221
  })]
217
222
  }),
218
- /* @__PURE__ */ S(h, {
219
- control: /* @__PURE__ */ S(l, {
220
- checked: V.isMilestone,
221
- onChange: (e) => G(e.target.checked),
223
+ /* @__PURE__ */ w(s, {
224
+ "data-testid": "gantt-dialog-field-progress-wrapper",
225
+ children: [/* @__PURE__ */ w(s, {
226
+ sx: {
227
+ display: "flex",
228
+ justifyContent: "space-between",
229
+ alignItems: "baseline",
230
+ mb: .25
231
+ },
232
+ children: [/* @__PURE__ */ C(S, {
233
+ variant: "caption",
234
+ color: H.isMilestone ? "text.disabled" : "text.secondary",
235
+ children: N.dialogFieldProgress ?? "Fortschritt (%)"
236
+ }), /* @__PURE__ */ w(S, {
237
+ variant: "caption",
238
+ sx: { fontWeight: 600 },
239
+ color: H.isMilestone ? "text.disabled" : "text.primary",
240
+ children: [H.progress, " %"]
241
+ })]
242
+ }), /* @__PURE__ */ C(y, {
243
+ value: H.progress,
244
+ onChange: (e, t) => U((e) => ({
245
+ ...e,
246
+ progress: t
247
+ })),
248
+ min: 0,
249
+ max: 100,
250
+ step: 1,
251
+ disabled: H.isMilestone,
252
+ size: "small",
253
+ marks: [
254
+ { value: 0 },
255
+ { value: 25 },
256
+ { value: 50 },
257
+ { value: 75 },
258
+ { value: 100 }
259
+ ],
260
+ "aria-label": N.dialogFieldProgress ?? "Fortschritt (%)",
261
+ "data-testid": "gantt-dialog-field-progress"
262
+ })]
263
+ }),
264
+ /* @__PURE__ */ C(h, {
265
+ control: /* @__PURE__ */ C(l, {
266
+ checked: H.isMilestone,
267
+ onChange: (e) => K(e.target.checked),
222
268
  size: "small",
223
269
  "data-testid": "gantt-dialog-field-milestone"
224
270
  }),
225
- label: M.dialogFieldMilestone
271
+ label: N.dialogFieldMilestone
226
272
  }),
227
- /* @__PURE__ */ C(m, {
273
+ /* @__PURE__ */ w(m, {
228
274
  size: "small",
229
275
  fullWidth: !0,
230
- children: [/* @__PURE__ */ S(g, { children: M.dialogFieldParent }), /* @__PURE__ */ C(v, {
231
- value: V.parentId,
232
- label: M.dialogFieldParent,
233
- onChange: (e) => H((t) => ({
276
+ children: [/* @__PURE__ */ C(g, { children: N.dialogFieldParent }), /* @__PURE__ */ w(v, {
277
+ value: H.parentId,
278
+ label: N.dialogFieldParent,
279
+ onChange: (e) => U((t) => ({
234
280
  ...t,
235
281
  parentId: e.target.value
236
282
  })),
237
283
  inputProps: { "data-testid": "gantt-dialog-field-parent" },
238
284
  MenuProps: { slotProps: { paper: { sx: { maxHeight: 280 } } } },
239
- children: [/* @__PURE__ */ S(_, {
285
+ children: [/* @__PURE__ */ C(_, {
240
286
  value: "",
241
- children: M.dialogFieldParentNone
242
- }), L.map((e) => /* @__PURE__ */ S(_, {
287
+ children: N.dialogFieldParentNone
288
+ }), R.map((e) => /* @__PURE__ */ C(_, {
243
289
  value: e.id,
244
290
  sx: { minWidth: 0 },
245
- children: /* @__PURE__ */ C(s, {
291
+ children: /* @__PURE__ */ w(s, {
246
292
  sx: {
247
293
  display: "flex",
248
294
  alignItems: "center",
@@ -252,7 +298,7 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
252
298
  width: "100%",
253
299
  overflow: "hidden"
254
300
  },
255
- children: [e.depth > 0 && /* @__PURE__ */ S(x, {
301
+ children: [e.depth > 0 && /* @__PURE__ */ C(S, {
256
302
  component: "span",
257
303
  variant: "caption",
258
304
  sx: {
@@ -261,32 +307,32 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
261
307
  flexShrink: 0
262
308
  },
263
309
  children: "└"
264
- }), /* @__PURE__ */ S(D, { label: e.name })]
310
+ }), /* @__PURE__ */ C(O, { label: e.name })]
265
311
  })
266
312
  }, e.id))]
267
313
  })]
268
314
  }),
269
- /* @__PURE__ */ C(m, {
315
+ /* @__PURE__ */ w(m, {
270
316
  size: "small",
271
317
  fullWidth: !0,
272
- children: [/* @__PURE__ */ S(g, { children: M.dialogFieldDependencies }), /* @__PURE__ */ S(v, {
318
+ children: [/* @__PURE__ */ C(g, { children: N.dialogFieldDependencies }), /* @__PURE__ */ C(v, {
273
319
  multiple: !0,
274
- value: V.dependencies,
275
- label: M.dialogFieldDependencies,
320
+ value: H.dependencies,
321
+ label: N.dialogFieldDependencies,
276
322
  onChange: (e) => {
277
323
  let t = e.target.value;
278
- H((e) => ({
324
+ U((e) => ({
279
325
  ...e,
280
326
  dependencies: typeof t == "string" ? t.split(",") : t
281
327
  }));
282
328
  },
283
329
  inputProps: { "data-testid": "gantt-dialog-field-dependencies" },
284
- renderValue: (e) => e.length === 0 ? M.dialogFieldDependenciesNone : e.map((e) => F.find((t) => t.id === e)?.name ?? e).join(", "),
330
+ renderValue: (e) => e.length === 0 ? N.dialogFieldDependenciesNone : e.map((e) => I.find((t) => t.id === e)?.name ?? e).join(", "),
285
331
  MenuProps: { slotProps: { paper: { sx: { maxHeight: 280 } } } },
286
- children: z.map((e) => /* @__PURE__ */ S(_, {
332
+ children: B.map((e) => /* @__PURE__ */ C(_, {
287
333
  value: e.id,
288
334
  sx: { minWidth: 0 },
289
- children: /* @__PURE__ */ C(s, {
335
+ children: /* @__PURE__ */ w(s, {
290
336
  sx: {
291
337
  display: "flex",
292
338
  alignItems: "center",
@@ -296,7 +342,7 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
296
342
  width: "100%",
297
343
  overflow: "hidden"
298
344
  },
299
- children: [e.depth > 0 && /* @__PURE__ */ S(x, {
345
+ children: [e.depth > 0 && /* @__PURE__ */ C(S, {
300
346
  component: "span",
301
347
  variant: "caption",
302
348
  sx: {
@@ -305,25 +351,25 @@ function O({ open: a, mode: b, initialTask: O, defaultParentId: k, onSave: A, on
305
351
  flexShrink: 0
306
352
  },
307
353
  children: "└"
308
- }), /* @__PURE__ */ S(D, { label: e.name })]
354
+ }), /* @__PURE__ */ C(O, { label: e.name })]
309
355
  })
310
356
  }, e.id))
311
357
  })]
312
358
  })
313
359
  ]
314
360
  }),
315
- /* @__PURE__ */ C(d, { children: [/* @__PURE__ */ S(c, {
316
- onClick: j,
317
- children: M.dialogCancel
318
- }), /* @__PURE__ */ S(c, {
319
- onClick: q,
361
+ /* @__PURE__ */ w(d, { children: [/* @__PURE__ */ C(c, {
362
+ onClick: M,
363
+ children: N.dialogCancel
364
+ }), /* @__PURE__ */ C(c, {
365
+ onClick: J,
320
366
  variant: "contained",
321
- disabled: !K,
367
+ disabled: !q,
322
368
  "data-testid": "gantt-dialog-save",
323
- children: M.dialogSave
369
+ children: N.dialogSave
324
370
  })] })
325
371
  ]
326
372
  });
327
373
  }
328
374
  //#endregion
329
- export { O as GanttTaskDialog };
375
+ export { k as GanttTaskDialog };