@mieweb/ui 0.10.0-dev.5 → 0.10.0-dev.7
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/agent/mieweb-ui.instructions.md +13 -1
- package/dist/brands/index.cjs +13 -13
- package/dist/brands/index.js +1 -1
- package/dist/chunk-3YBS4WUQ.js +52 -0
- package/dist/chunk-3YBS4WUQ.js.map +1 -0
- package/dist/chunk-4IS3QCOQ.cjs +453 -0
- package/dist/chunk-4IS3QCOQ.cjs.map +1 -0
- package/dist/chunk-4NCDU5IG.cjs +56 -0
- package/dist/chunk-4NCDU5IG.cjs.map +1 -0
- package/dist/chunk-76TBQDED.js +166 -0
- package/dist/chunk-76TBQDED.js.map +1 -0
- package/dist/chunk-DZ5HFLRC.js +258 -0
- package/dist/chunk-DZ5HFLRC.js.map +1 -0
- package/dist/chunk-G4D6CLBT.js +333 -0
- package/dist/chunk-G4D6CLBT.js.map +1 -0
- package/dist/chunk-IT775BYG.js +179 -0
- package/dist/chunk-IT775BYG.js.map +1 -0
- package/dist/{chunk-ELPW32ZI.cjs → chunk-KQUI4BGS.cjs} +3 -3
- package/dist/{chunk-ELPW32ZI.cjs.map → chunk-KQUI4BGS.cjs.map} +1 -1
- package/dist/{chunk-WNM7IZJ7.js → chunk-MNILXWVY.js} +2 -2
- package/dist/{chunk-WNM7IZJ7.js.map → chunk-MNILXWVY.js.map} +1 -1
- package/dist/chunk-OCSCBB52.cjs +188 -0
- package/dist/chunk-OCSCBB52.cjs.map +1 -0
- package/dist/{chunk-2YCERQWC.js → chunk-TVTIGV7Q.js} +3 -3
- package/dist/{chunk-2YCERQWC.js.map → chunk-TVTIGV7Q.js.map} +1 -1
- package/dist/chunk-URAQIF67.cjs +356 -0
- package/dist/chunk-URAQIF67.cjs.map +1 -0
- package/dist/chunk-VINZZQBD.cjs +323 -0
- package/dist/chunk-VINZZQBD.cjs.map +1 -0
- package/dist/{chunk-U42F3HLE.cjs → chunk-XCENM6ED.cjs} +12 -2
- package/dist/chunk-XCENM6ED.cjs.map +1 -0
- package/dist/chunk-XDIMTPZU.cjs +202 -0
- package/dist/chunk-XDIMTPZU.cjs.map +1 -0
- package/dist/{chunk-JI244Y7C.js → chunk-XEPDIFEA.js} +12 -2
- package/dist/chunk-XEPDIFEA.js.map +1 -0
- package/dist/chunk-XVW5DPPP.js +429 -0
- package/dist/chunk-XVW5DPPP.js.map +1 -0
- package/dist/chunk-XZNN3S3S.cjs +281 -0
- package/dist/chunk-XZNN3S3S.cjs.map +1 -0
- package/dist/chunk-Y4QNLW7W.js +300 -0
- package/dist/chunk-Y4QNLW7W.js.map +1 -0
- package/dist/{chunk-2QKBTPUC.cjs → chunk-ZPSJ2UV6.cjs} +2 -2
- package/dist/{chunk-2QKBTPUC.cjs.map → chunk-ZPSJ2UV6.cjs.map} +1 -1
- package/dist/components/BoardView/index.cjs +24 -0
- package/dist/components/BoardView/index.cjs.map +1 -0
- package/dist/components/BoardView/index.d.cts +42 -0
- package/dist/components/BoardView/index.d.ts +42 -0
- package/dist/components/BoardView/index.js +7 -0
- package/dist/components/BoardView/index.js.map +1 -0
- package/dist/components/CalendarView/index.cjs +22 -0
- package/dist/components/CalendarView/index.cjs.map +1 -0
- package/dist/components/CalendarView/index.d.cts +40 -0
- package/dist/components/CalendarView/index.d.ts +40 -0
- package/dist/components/CalendarView/index.js +9 -0
- package/dist/components/CalendarView/index.js.map +1 -0
- package/dist/components/GanttView/index.cjs +20 -0
- package/dist/components/GanttView/index.cjs.map +1 -0
- package/dist/components/GanttView/index.d.cts +37 -0
- package/dist/components/GanttView/index.d.ts +37 -0
- package/dist/components/GanttView/index.js +7 -0
- package/dist/components/GanttView/index.js.map +1 -0
- package/dist/components/ListView/index.cjs +22 -0
- package/dist/components/ListView/index.cjs.map +1 -0
- package/dist/components/ListView/index.d.cts +37 -0
- package/dist/components/ListView/index.d.ts +37 -0
- package/dist/components/ListView/index.js +9 -0
- package/dist/components/ListView/index.js.map +1 -0
- package/dist/components/Markdown/index.cjs +15 -15
- package/dist/components/Markdown/index.js +3 -3
- package/dist/components/QuickAction/index.d.cts +1 -1
- package/dist/components/QuickAction/index.d.ts +1 -1
- package/dist/components/ViewSet/index.cjs +23 -0
- package/dist/components/ViewSet/index.cjs.map +1 -0
- package/dist/components/ViewSet/index.d.cts +89 -0
- package/dist/components/ViewSet/index.d.ts +89 -0
- package/dist/components/ViewSet/index.js +14 -0
- package/dist/components/ViewSet/index.js.map +1 -0
- package/dist/components/ViewSwitcher/index.cjs +20 -0
- package/dist/components/ViewSwitcher/index.cjs.map +1 -0
- package/dist/components/ViewSwitcher/index.d.cts +40 -0
- package/dist/components/ViewSwitcher/index.d.ts +40 -0
- package/dist/components/ViewSwitcher/index.js +7 -0
- package/dist/components/ViewSwitcher/index.js.map +1 -0
- package/dist/esheet.cjs +5 -5
- package/dist/esheet.js +2 -2
- package/dist/hooks/index.cjs +5 -5
- package/dist/hooks/index.js +1 -1
- package/dist/index.cjs +439 -372
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +57 -50
- package/dist/index.js.map +1 -1
- package/dist/kerebron.cjs +34 -9
- package/dist/kerebron.cjs.map +1 -1
- package/dist/kerebron.d.cts +21 -0
- package/dist/kerebron.d.ts +21 -0
- package/dist/kerebron.js +34 -9
- package/dist/kerebron.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -4
- package/dist/tailwind-preset.js +1 -1
- package/dist/types-CbWXIKbe.d.cts +119 -0
- package/dist/types-CbWXIKbe.d.ts +119 -0
- package/package.json +6 -1
- package/dist/chunk-JI244Y7C.js.map +0 -1
- package/dist/chunk-U42F3HLE.cjs.map +0 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk4NCDU5IG_cjs = require('./chunk-4NCDU5IG.cjs');
|
|
4
|
+
var chunkXXVUHLQN_cjs = require('./chunk-XXVUHLQN.cjs');
|
|
5
|
+
var chunkL7L5S2HO_cjs = require('./chunk-L7L5S2HO.cjs');
|
|
6
|
+
var chunkVNYW4C4J_cjs = require('./chunk-VNYW4C4J.cjs');
|
|
7
|
+
var chunkS5RVSXDV_cjs = require('./chunk-S5RVSXDV.cjs');
|
|
8
|
+
var React = require('react');
|
|
9
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
10
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
+
|
|
12
|
+
function _interopNamespace(e) {
|
|
13
|
+
if (e && e.__esModule) return e;
|
|
14
|
+
var n = Object.create(null);
|
|
15
|
+
if (e) {
|
|
16
|
+
Object.keys(e).forEach(function (k) {
|
|
17
|
+
if (k !== 'default') {
|
|
18
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return e[k]; }
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
n.default = e;
|
|
27
|
+
return Object.freeze(n);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
31
|
+
|
|
32
|
+
var itemVariants = classVarianceAuthority.cva(
|
|
33
|
+
[
|
|
34
|
+
"flex w-full items-start gap-3 border-b border-border px-3 text-start",
|
|
35
|
+
"last:border-b-0",
|
|
36
|
+
"transition-colors",
|
|
37
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
38
|
+
],
|
|
39
|
+
{
|
|
40
|
+
variants: {
|
|
41
|
+
density: {
|
|
42
|
+
comfortable: "py-3",
|
|
43
|
+
compact: "py-2"
|
|
44
|
+
},
|
|
45
|
+
interactive: {
|
|
46
|
+
true: "cursor-pointer hover:bg-muted",
|
|
47
|
+
false: ""
|
|
48
|
+
},
|
|
49
|
+
selected: {
|
|
50
|
+
true: "bg-primary-500/10",
|
|
51
|
+
false: ""
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
defaultVariants: {
|
|
55
|
+
density: "comfortable",
|
|
56
|
+
interactive: false,
|
|
57
|
+
selected: false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
function buildGroups(items, groupBy, accessors, ungrouped, stages) {
|
|
62
|
+
if (groupBy === "none") return [{ id: "", label: "", items }];
|
|
63
|
+
const read = groupBy === "status" ? accessors.getStatus : accessors.getGroup;
|
|
64
|
+
if (!read) return [{ id: "", label: "", items }];
|
|
65
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
66
|
+
for (const item of items) {
|
|
67
|
+
const key = read(item) ?? "";
|
|
68
|
+
const bucket = buckets.get(key);
|
|
69
|
+
if (bucket) bucket.push(item);
|
|
70
|
+
else buckets.set(key, [item]);
|
|
71
|
+
}
|
|
72
|
+
const groups = [];
|
|
73
|
+
for (const stage of (groupBy === "status" ? stages : void 0) ?? []) {
|
|
74
|
+
groups.push({
|
|
75
|
+
id: stage.id,
|
|
76
|
+
label: stage.label,
|
|
77
|
+
accent: stage.accent,
|
|
78
|
+
items: buckets.get(stage.id) ?? []
|
|
79
|
+
});
|
|
80
|
+
buckets.delete(stage.id);
|
|
81
|
+
}
|
|
82
|
+
for (const [key, bucket] of buckets) {
|
|
83
|
+
groups.push({ id: key, label: key || ungrouped, items: bucket });
|
|
84
|
+
}
|
|
85
|
+
return groups;
|
|
86
|
+
}
|
|
87
|
+
function ListView({
|
|
88
|
+
items,
|
|
89
|
+
accessors,
|
|
90
|
+
loading = false,
|
|
91
|
+
error = null,
|
|
92
|
+
selectedId = null,
|
|
93
|
+
onOpen,
|
|
94
|
+
getHref,
|
|
95
|
+
renderItem,
|
|
96
|
+
emptyState,
|
|
97
|
+
labels,
|
|
98
|
+
stages,
|
|
99
|
+
groupBy = stages ? "status" : "none",
|
|
100
|
+
defaultCollapsedGroups,
|
|
101
|
+
onRetry,
|
|
102
|
+
density,
|
|
103
|
+
className,
|
|
104
|
+
classNames,
|
|
105
|
+
headingLevel: Heading = "h3"
|
|
106
|
+
}) {
|
|
107
|
+
const text = { ...chunk4NCDU5IG_cjs.defaultViewLabels, ...labels };
|
|
108
|
+
const baseId = React__namespace.useId();
|
|
109
|
+
const [collapsed, setCollapsed] = React__namespace.useState(
|
|
110
|
+
() => new Set(defaultCollapsedGroups ?? [])
|
|
111
|
+
);
|
|
112
|
+
const groups = React__namespace.useMemo(
|
|
113
|
+
() => buildGroups(items, groupBy, accessors, text.ungrouped, stages),
|
|
114
|
+
[items, groupBy, accessors, text.ungrouped, stages]
|
|
115
|
+
);
|
|
116
|
+
const state = (content) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
"data-slot": "list-view-state",
|
|
120
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
121
|
+
"text-muted-foreground flex flex-col items-center justify-center gap-2 px-4 py-10 text-center text-sm",
|
|
122
|
+
classNames?.state
|
|
123
|
+
),
|
|
124
|
+
children: content
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
let body;
|
|
128
|
+
if (error) {
|
|
129
|
+
body = state(
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
131
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-destructive", children: text.error }),
|
|
132
|
+
onRetry && /* @__PURE__ */ jsxRuntime.jsx(chunkVNYW4C4J_cjs.Button, { variant: "ghost", size: "sm", onClick: onRetry, children: text.retry })
|
|
133
|
+
] })
|
|
134
|
+
);
|
|
135
|
+
} else if (loading) {
|
|
136
|
+
body = state(
|
|
137
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
|
|
138
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkXXVUHLQN_cjs.Spinner, { size: "sm", label: text.loading }),
|
|
139
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: text.loading })
|
|
140
|
+
] })
|
|
141
|
+
);
|
|
142
|
+
} else if (items.length === 0) {
|
|
143
|
+
body = emptyState ?? state(text.empty);
|
|
144
|
+
} else {
|
|
145
|
+
body = groups.map((group, groupIndex) => {
|
|
146
|
+
const isCollapsed = collapsed.has(group.id);
|
|
147
|
+
const headerId = `${baseId}-group-${groupIndex}`;
|
|
148
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
149
|
+
"section",
|
|
150
|
+
{
|
|
151
|
+
"data-slot": "list-view-group",
|
|
152
|
+
className: chunkS5RVSXDV_cjs.cn(classNames?.group),
|
|
153
|
+
children: [
|
|
154
|
+
group.label && /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "sticky top-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
155
|
+
"button",
|
|
156
|
+
{
|
|
157
|
+
type: "button",
|
|
158
|
+
id: headerId,
|
|
159
|
+
"aria-expanded": !isCollapsed,
|
|
160
|
+
onClick: () => setCollapsed((prev) => {
|
|
161
|
+
const next = new Set(prev);
|
|
162
|
+
if (!next.delete(group.id)) next.add(group.id);
|
|
163
|
+
return next;
|
|
164
|
+
}),
|
|
165
|
+
"data-slot": "list-view-group-header",
|
|
166
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
167
|
+
"border-border bg-muted text-muted-foreground flex w-full items-center gap-2 border-b px-3 py-2 text-start text-xs font-semibold tracking-wide uppercase",
|
|
168
|
+
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset",
|
|
169
|
+
classNames?.groupHeader
|
|
170
|
+
),
|
|
171
|
+
children: [
|
|
172
|
+
isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
173
|
+
chunkL7L5S2HO_cjs.ChevronRight,
|
|
174
|
+
{
|
|
175
|
+
className: "size-3.5 rtl:rotate-180",
|
|
176
|
+
"aria-hidden": true
|
|
177
|
+
}
|
|
178
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(chunkL7L5S2HO_cjs.ChevronDown, { className: "size-3.5", "aria-hidden": true }),
|
|
179
|
+
group.accent && /* @__PURE__ */ jsxRuntime.jsx(
|
|
180
|
+
"span",
|
|
181
|
+
{
|
|
182
|
+
"aria-hidden": true,
|
|
183
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
184
|
+
"size-2 shrink-0 rounded-full",
|
|
185
|
+
chunk4NCDU5IG_cjs.accentClasses[group.accent].marker
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: group.label }),
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ms-auto font-normal tabular-nums", children: group.items.length })
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
) }),
|
|
194
|
+
!isCollapsed && /* @__PURE__ */ jsxRuntime.jsxs("ul", { "aria-labelledby": group.label ? headerId : void 0, children: [
|
|
195
|
+
group.items.map((item) => {
|
|
196
|
+
const id = accessors.getId(item);
|
|
197
|
+
const selected = id === selectedId;
|
|
198
|
+
const accent = accessors.getAccent?.(item);
|
|
199
|
+
const subtitle = accessors.getSubtitle?.(item);
|
|
200
|
+
const content = renderItem?.(item, { view: "list" }) ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
201
|
+
accent && /* @__PURE__ */ jsxRuntime.jsx(
|
|
202
|
+
"span",
|
|
203
|
+
{
|
|
204
|
+
"aria-hidden": true,
|
|
205
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
206
|
+
"mt-1.5 size-2 shrink-0 rounded-full",
|
|
207
|
+
chunk4NCDU5IG_cjs.accentClasses[accent].marker
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
),
|
|
211
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
212
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground block truncate font-medium", children: accessors.getTitle(item) }),
|
|
213
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground block truncate text-sm", children: subtitle })
|
|
214
|
+
] })
|
|
215
|
+
] });
|
|
216
|
+
const classes = chunkS5RVSXDV_cjs.cn(
|
|
217
|
+
itemVariants({
|
|
218
|
+
density,
|
|
219
|
+
interactive: Boolean(onOpen || getHref),
|
|
220
|
+
selected
|
|
221
|
+
}),
|
|
222
|
+
classNames?.item,
|
|
223
|
+
selected && classNames?.selectedItem
|
|
224
|
+
);
|
|
225
|
+
const href = getHref?.(id, item);
|
|
226
|
+
return /* @__PURE__ */ jsxRuntime.jsx("li", { children: href ? (
|
|
227
|
+
// An anchor, not a handler, so the row is middle-clickable
|
|
228
|
+
// and crawlable; onOpen still runs for router navigation.
|
|
229
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
230
|
+
"a",
|
|
231
|
+
{
|
|
232
|
+
href,
|
|
233
|
+
"aria-current": selected ? "true" : void 0,
|
|
234
|
+
"data-slot": "list-view-item",
|
|
235
|
+
className: classes,
|
|
236
|
+
onClick: (event) => {
|
|
237
|
+
if (!onOpen || event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0)
|
|
238
|
+
return;
|
|
239
|
+
event.preventDefault();
|
|
240
|
+
onOpen(id, item);
|
|
241
|
+
},
|
|
242
|
+
children: content
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
) : onOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
246
|
+
"button",
|
|
247
|
+
{
|
|
248
|
+
type: "button",
|
|
249
|
+
"aria-current": selected ? "true" : void 0,
|
|
250
|
+
"data-slot": "list-view-item",
|
|
251
|
+
className: classes,
|
|
252
|
+
onClick: () => onOpen(id, item),
|
|
253
|
+
children: content
|
|
254
|
+
}
|
|
255
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "list-view-item", className: classes, children: content }) }, id);
|
|
256
|
+
}),
|
|
257
|
+
group.items.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-muted-foreground px-3 py-2 text-sm", children: text.empty })
|
|
258
|
+
] })
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
group.id
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
266
|
+
"div",
|
|
267
|
+
{
|
|
268
|
+
"data-slot": "list-view",
|
|
269
|
+
className: chunkS5RVSXDV_cjs.cn(
|
|
270
|
+
"border-border bg-card overflow-hidden rounded-lg border",
|
|
271
|
+
className
|
|
272
|
+
),
|
|
273
|
+
children: body
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
exports.ListView = ListView;
|
|
279
|
+
exports.itemVariants = itemVariants;
|
|
280
|
+
//# sourceMappingURL=chunk-XZNN3S3S.cjs.map
|
|
281
|
+
//# sourceMappingURL=chunk-XZNN3S3S.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ListView/ListView.tsx"],"names":["cva","defaultViewLabels","React","jsx","cn","jsxs","Fragment","Button","Spinner","ChevronRight","ChevronDown","accentClasses"],"mappings":"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","file":"chunk-XZNN3S3S.cjs","sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils/cn';\nimport { Button } from '../Button';\nimport { Spinner } from '../Spinner';\nimport { ChevronDownIcon, ChevronRightIcon } from '../Icons';\nimport {\n accentClasses,\n defaultViewLabels,\n type Stage,\n type ViewBaseProps,\n} from '../../views/types';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type ListViewSlot =\n | 'group'\n | 'groupHeader'\n | 'item'\n | 'selectedItem'\n | 'state';\n\nexport interface ListViewProps<T>\n extends ViewBaseProps<T>, VariantProps<typeof itemVariants> {\n /**\n * Group rows by `accessors.getStatus`, using these stages for order and\n * labels. Items whose status matches no stage are appended under their own\n * heading rather than dropped.\n */\n stages?: readonly Stage[];\n /** Group by `accessors.getGroup` instead of by stage. */\n groupBy?: 'status' | 'group' | 'none';\n /** Groups that start collapsed. Uncontrolled; the user can reopen them. */\n defaultCollapsedGroups?: readonly string[];\n /** Retries the failed load. Renders the retry action only when provided. */\n onRetry?: () => void;\n classNames?: Partial<Record<ListViewSlot, string>>;\n /** Heading level for group headers, under the page's own heading. */\n headingLevel?: 'h2' | 'h3' | 'h4';\n}\n\ninterface Group<T> {\n id: string;\n label: string;\n accent?: Stage['accent'];\n items: T[];\n}\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst itemVariants = cva(\n [\n 'flex w-full items-start gap-3 border-b border-border px-3 text-start',\n 'last:border-b-0',\n 'transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring',\n ],\n {\n variants: {\n density: {\n comfortable: 'py-3',\n compact: 'py-2',\n },\n interactive: {\n true: 'cursor-pointer hover:bg-muted',\n false: '',\n },\n selected: {\n true: 'bg-primary-500/10',\n false: '',\n },\n },\n defaultVariants: {\n density: 'comfortable',\n interactive: false,\n selected: false,\n },\n }\n);\n\n// =============================================================================\n// Grouping\n// =============================================================================\n\nfunction buildGroups<T>(\n items: T[],\n groupBy: 'status' | 'group' | 'none',\n accessors: ListViewProps<T>['accessors'],\n ungrouped: string,\n stages?: readonly Stage[]\n): Group<T>[] {\n if (groupBy === 'none') return [{ id: '', label: '', items }];\n\n const read = groupBy === 'status' ? accessors.getStatus : accessors.getGroup;\n if (!read) return [{ id: '', label: '', items }];\n\n const buckets = new Map<string, T[]>();\n for (const item of items) {\n const key = read(item) ?? '';\n const bucket = buckets.get(key);\n if (bucket) bucket.push(item);\n else buckets.set(key, [item]);\n }\n\n const groups: Group<T>[] = [];\n // Stages fix the order, and an empty stage still shows — a board column that\n // disappears when it empties hides the fact that the stage exists. This only\n // applies to `groupBy=\"status\"`: stages name statuses, so seeding them under\n // `groupBy=\"group\"` would print an empty \"Backlog\"/\"In progress\" above the\n // real buckets. `ViewSet` always passes its shared stages, so that case is\n // reachable with nothing more than `listProps={{ groupBy: 'group' }}`.\n for (const stage of (groupBy === 'status' ? stages : undefined) ?? []) {\n groups.push({\n id: stage.id,\n label: stage.label,\n accent: stage.accent,\n items: buckets.get(stage.id) ?? [],\n });\n buckets.delete(stage.id);\n }\n for (const [key, bucket] of buckets) {\n groups.push({ id: key, label: key || ungrouped, items: bucket });\n }\n return groups;\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\n/**\n * Declared `parameters.catalog.collection` — the three load states below are\n * part of this component's API, not decoration.\n */\nexport function ListView<T>({\n items,\n accessors,\n loading = false,\n error = null,\n selectedId = null,\n onOpen,\n getHref,\n renderItem,\n emptyState,\n labels,\n stages,\n groupBy = stages ? 'status' : 'none',\n defaultCollapsedGroups,\n onRetry,\n density,\n className,\n classNames,\n headingLevel: Heading = 'h3',\n}: ListViewProps<T>) {\n const text = { ...defaultViewLabels, ...labels };\n // Ids come from position, not from the status text: two distinct statuses can\n // normalise to the same string, and a duplicate id makes `aria-labelledby`\n // resolve to the wrong heading.\n const baseId = React.useId();\n const [collapsed, setCollapsed] = React.useState<Set<string>>(\n () => new Set(defaultCollapsedGroups ?? [])\n );\n\n const groups = React.useMemo(\n () => buildGroups(items, groupBy, accessors, text.ungrouped, stages),\n [items, groupBy, accessors, text.ungrouped, stages]\n );\n\n const state = (content: React.ReactNode) => (\n <div\n data-slot=\"list-view-state\"\n className={cn(\n 'text-muted-foreground flex flex-col items-center justify-center gap-2 px-4 py-10 text-center text-sm',\n classNames?.state\n )}\n >\n {content}\n </div>\n );\n\n let body: React.ReactNode;\n if (error) {\n body = state(\n <>\n <p role=\"alert\" className=\"text-destructive\">\n {text.error}\n </p>\n {onRetry && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onRetry}>\n {text.retry}\n </Button>\n )}\n </>\n );\n } else if (loading) {\n // Spinner is the status region and carries the accessible name; the visible\n // copy beside it would otherwise be announced twice.\n body = state(\n <span className=\"flex items-center gap-2\">\n <Spinner size=\"sm\" label={text.loading} />\n <span aria-hidden>{text.loading}</span>\n </span>\n );\n } else if (items.length === 0) {\n body = emptyState ?? state(text.empty);\n } else {\n body = groups.map((group, groupIndex) => {\n const isCollapsed = collapsed.has(group.id);\n const headerId = `${baseId}-group-${groupIndex}`;\n return (\n <section\n key={group.id}\n data-slot=\"list-view-group\"\n className={cn(classNames?.group)}\n >\n {group.label && (\n <Heading className=\"sticky top-0 z-10\">\n <button\n type=\"button\"\n id={headerId}\n aria-expanded={!isCollapsed}\n onClick={() =>\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (!next.delete(group.id)) next.add(group.id);\n return next;\n })\n }\n data-slot=\"list-view-group-header\"\n className={cn(\n 'border-border bg-muted text-muted-foreground flex w-full items-center gap-2 border-b px-3 py-2 text-start text-xs font-semibold tracking-wide uppercase',\n 'focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset',\n classNames?.groupHeader\n )}\n >\n {isCollapsed ? (\n <ChevronRightIcon\n className=\"size-3.5 rtl:rotate-180\"\n aria-hidden\n />\n ) : (\n <ChevronDownIcon className=\"size-3.5\" aria-hidden />\n )}\n {group.accent && (\n <span\n aria-hidden\n className={cn(\n 'size-2 shrink-0 rounded-full',\n accentClasses[group.accent].marker\n )}\n />\n )}\n <span>{group.label}</span>\n <span className=\"ms-auto font-normal tabular-nums\">\n {group.items.length}\n </span>\n </button>\n </Heading>\n )}\n {!isCollapsed && (\n <ul aria-labelledby={group.label ? headerId : undefined}>\n {group.items.map((item) => {\n const id = accessors.getId(item);\n const selected = id === selectedId;\n const accent = accessors.getAccent?.(item);\n const subtitle = accessors.getSubtitle?.(item);\n const content = renderItem?.(item, { view: 'list' }) ?? (\n <>\n {accent && (\n <span\n aria-hidden\n className={cn(\n 'mt-1.5 size-2 shrink-0 rounded-full',\n accentClasses[accent].marker\n )}\n />\n )}\n <span className=\"min-w-0 flex-1\">\n <span className=\"text-foreground block truncate font-medium\">\n {accessors.getTitle(item)}\n </span>\n {subtitle && (\n <span className=\"text-muted-foreground block truncate text-sm\">\n {subtitle}\n </span>\n )}\n </span>\n </>\n );\n const classes = cn(\n itemVariants({\n density,\n interactive: Boolean(onOpen || getHref),\n selected,\n }),\n classNames?.item,\n selected && classNames?.selectedItem\n );\n const href = getHref?.(id, item);\n return (\n <li key={id}>\n {href ? (\n // An anchor, not a handler, so the row is middle-clickable\n // and crawlable; onOpen still runs for router navigation.\n <a\n href={href}\n aria-current={selected ? 'true' : undefined}\n data-slot=\"list-view-item\"\n className={classes}\n onClick={(event) => {\n if (\n !onOpen ||\n event.defaultPrevented ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.button !== 0\n )\n return;\n event.preventDefault();\n onOpen(id, item);\n }}\n >\n {content}\n </a>\n ) : onOpen ? (\n <button\n type=\"button\"\n aria-current={selected ? 'true' : undefined}\n data-slot=\"list-view-item\"\n className={classes}\n onClick={() => onOpen(id, item)}\n >\n {content}\n </button>\n ) : (\n <div data-slot=\"list-view-item\" className={classes}>\n {content}\n </div>\n )}\n </li>\n );\n })}\n {group.items.length === 0 && (\n <li className=\"text-muted-foreground px-3 py-2 text-sm\">\n {text.empty}\n </li>\n )}\n </ul>\n )}\n </section>\n );\n });\n }\n\n return (\n <div\n data-slot=\"list-view\"\n className={cn(\n 'border-border bg-card overflow-hidden rounded-lg border',\n className\n )}\n >\n {body}\n </div>\n );\n}\n\nexport { itemVariants as listViewItemVariants };\n"]}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { defaultViewLabels, toDateTime, accentClasses } from './chunk-3YBS4WUQ.js';
|
|
2
|
+
import { Spinner } from './chunk-UA7E7PDS.js';
|
|
3
|
+
import { cn } from './chunk-TQONQSJO.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { DateTime } from 'luxon';
|
|
6
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var defaultGanttLabels = {
|
|
9
|
+
...defaultViewLabels,
|
|
10
|
+
empty: "Nothing to place on the timeline",
|
|
11
|
+
chart: "Timeline",
|
|
12
|
+
undated: "{count} without dates"
|
|
13
|
+
};
|
|
14
|
+
var CADENCE_UNIT = {
|
|
15
|
+
day: "day",
|
|
16
|
+
week: "week",
|
|
17
|
+
month: "month",
|
|
18
|
+
quarter: "quarter"
|
|
19
|
+
};
|
|
20
|
+
var CADENCE_FORMAT = {
|
|
21
|
+
day: "d LLL",
|
|
22
|
+
week: "'W'W",
|
|
23
|
+
month: "LLL",
|
|
24
|
+
quarter: "'Q'q yyyy"
|
|
25
|
+
};
|
|
26
|
+
function GanttView({
|
|
27
|
+
items,
|
|
28
|
+
accessors,
|
|
29
|
+
loading = false,
|
|
30
|
+
error = null,
|
|
31
|
+
selectedId = null,
|
|
32
|
+
onOpen,
|
|
33
|
+
getHref,
|
|
34
|
+
renderItem,
|
|
35
|
+
emptyState,
|
|
36
|
+
labels,
|
|
37
|
+
cadence = "week",
|
|
38
|
+
rangeStart,
|
|
39
|
+
rangeEnd,
|
|
40
|
+
groupByLane = false,
|
|
41
|
+
timeZone,
|
|
42
|
+
locale,
|
|
43
|
+
now,
|
|
44
|
+
className,
|
|
45
|
+
classNames,
|
|
46
|
+
headingLevel: Heading = "h3"
|
|
47
|
+
}) {
|
|
48
|
+
const text = { ...defaultGanttLabels, ...labels };
|
|
49
|
+
const zone = timeZone ?? DateTime.local().zoneName;
|
|
50
|
+
const unit = CADENCE_UNIT[cadence];
|
|
51
|
+
const today = React.useMemo(
|
|
52
|
+
() => DateTime.fromJSDate(now ?? /* @__PURE__ */ new Date(), { zone }).startOf("day"),
|
|
53
|
+
[now, zone]
|
|
54
|
+
);
|
|
55
|
+
const dated = React.useMemo(() => {
|
|
56
|
+
const out = [];
|
|
57
|
+
for (const item of items) {
|
|
58
|
+
const start = toDateTime(accessors.getStart?.(item), zone)?.startOf(
|
|
59
|
+
"day"
|
|
60
|
+
);
|
|
61
|
+
if (!start) continue;
|
|
62
|
+
const rawEnd = toDateTime(accessors.getEnd?.(item), zone)?.startOf("day");
|
|
63
|
+
const end = rawEnd ?? start;
|
|
64
|
+
out.push({
|
|
65
|
+
id: accessors.getId(item),
|
|
66
|
+
item,
|
|
67
|
+
start,
|
|
68
|
+
end: end < start ? start : end
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}, [items, accessors, zone]);
|
|
73
|
+
const undatedCount = items.length - dated.length;
|
|
74
|
+
const columns = React.useMemo(() => {
|
|
75
|
+
if (dated.length === 0 && !rangeStart) return [];
|
|
76
|
+
const explicitStart = rangeStart ? DateTime.fromJSDate(rangeStart, { zone }) : null;
|
|
77
|
+
const first = explicitStart ?? dated.reduce((min, d) => d.start < min ? d.start : min, dated[0].start);
|
|
78
|
+
const last = rangeEnd ? DateTime.fromJSDate(rangeEnd, { zone }) : dated.length > 0 ? dated.reduce((max, d) => d.end > max ? d.end : max, dated[0].end) : first;
|
|
79
|
+
const out = [];
|
|
80
|
+
let cursor = first.startOf(unit);
|
|
81
|
+
const stop = last.startOf(unit);
|
|
82
|
+
if (stop < cursor) return [cursor];
|
|
83
|
+
while (cursor <= stop && out.length < 200) {
|
|
84
|
+
out.push(cursor);
|
|
85
|
+
cursor = cursor.plus({ [`${unit}s`]: 1 });
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}, [dated, rangeStart, rangeEnd, unit, zone]);
|
|
89
|
+
const columnOf = React.useCallback(
|
|
90
|
+
(moment) => {
|
|
91
|
+
const target = moment.startOf(unit);
|
|
92
|
+
const index = columns.findIndex((c) => c.hasSame(target, unit));
|
|
93
|
+
return index >= 0 ? index : null;
|
|
94
|
+
},
|
|
95
|
+
[columns, unit]
|
|
96
|
+
);
|
|
97
|
+
const lanes = React.useMemo(() => {
|
|
98
|
+
const toBar = (d) => {
|
|
99
|
+
const last = columns.length - 1;
|
|
100
|
+
const from = columnOf(d.start);
|
|
101
|
+
const to = columnOf(d.end);
|
|
102
|
+
const start = from ?? (d.start < columns[0] ? 0 : null);
|
|
103
|
+
const end = to ?? (d.end > columns[last] ? last : null);
|
|
104
|
+
if (start === null || end === null || end < start) return null;
|
|
105
|
+
return {
|
|
106
|
+
id: d.id,
|
|
107
|
+
item: d.item,
|
|
108
|
+
column: start + 1,
|
|
109
|
+
span: end - start + 1
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
const bars = (source) => source.map(toBar).filter((b) => b !== null);
|
|
113
|
+
if (!groupByLane || !accessors.getGroup)
|
|
114
|
+
return [{ id: "", label: "", bars: bars(dated) }];
|
|
115
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const d of dated) {
|
|
117
|
+
const key = accessors.getGroup(d.item) ?? "";
|
|
118
|
+
const bucket = buckets.get(key);
|
|
119
|
+
if (bucket) bucket.push(d);
|
|
120
|
+
else buckets.set(key, [d]);
|
|
121
|
+
}
|
|
122
|
+
return [...buckets].map(([key, bucket]) => ({
|
|
123
|
+
id: key,
|
|
124
|
+
label: key || text.ungrouped,
|
|
125
|
+
bars: bars(bucket)
|
|
126
|
+
}));
|
|
127
|
+
}, [dated, groupByLane, accessors, columnOf, columns, text.ungrouped]);
|
|
128
|
+
const todayColumn = (columnOf(today) ?? -1) + 1;
|
|
129
|
+
const showToday = columns.length > 0 && today >= columns[0] && today <= columns[columns.length - 1].endOf(unit);
|
|
130
|
+
const state = (content) => /* @__PURE__ */ jsx(
|
|
131
|
+
"div",
|
|
132
|
+
{
|
|
133
|
+
"data-slot": "gantt-view-state",
|
|
134
|
+
className: cn(
|
|
135
|
+
"border-border bg-card text-muted-foreground flex flex-col items-center justify-center gap-2 rounded-lg border px-4 py-10 text-center text-sm",
|
|
136
|
+
classNames?.state
|
|
137
|
+
),
|
|
138
|
+
children: content
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
if (error) {
|
|
142
|
+
return state(
|
|
143
|
+
/* @__PURE__ */ jsx("p", { role: "alert", className: "text-destructive", children: text.error })
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (loading) {
|
|
147
|
+
return state(
|
|
148
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
149
|
+
/* @__PURE__ */ jsx(Spinner, { size: "sm", label: text.loading }),
|
|
150
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: text.loading })
|
|
151
|
+
] })
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (columns.length === 0) return /* @__PURE__ */ jsx(Fragment, { children: emptyState ?? state(text.empty) });
|
|
155
|
+
const gridTemplate = {
|
|
156
|
+
gridTemplateColumns: `repeat(${columns.length}, minmax(3.5rem, 1fr))`
|
|
157
|
+
};
|
|
158
|
+
return /* @__PURE__ */ jsxs(
|
|
159
|
+
"div",
|
|
160
|
+
{
|
|
161
|
+
"data-slot": "gantt-view",
|
|
162
|
+
className: cn(
|
|
163
|
+
"border-border bg-card overflow-hidden rounded-lg border",
|
|
164
|
+
className
|
|
165
|
+
),
|
|
166
|
+
children: [
|
|
167
|
+
/* @__PURE__ */ jsx(
|
|
168
|
+
"div",
|
|
169
|
+
{
|
|
170
|
+
className: "overflow-x-auto",
|
|
171
|
+
role: "group",
|
|
172
|
+
"aria-label": text.chart,
|
|
173
|
+
tabIndex: 0,
|
|
174
|
+
children: /* @__PURE__ */ jsxs("div", { className: "min-w-max", children: [
|
|
175
|
+
/* @__PURE__ */ jsx(
|
|
176
|
+
"div",
|
|
177
|
+
{
|
|
178
|
+
"data-slot": "gantt-view-header",
|
|
179
|
+
className: cn(
|
|
180
|
+
"border-border bg-muted/40 grid border-b",
|
|
181
|
+
classNames?.header
|
|
182
|
+
),
|
|
183
|
+
style: gridTemplate,
|
|
184
|
+
children: columns.map((column) => /* @__PURE__ */ jsx(
|
|
185
|
+
"div",
|
|
186
|
+
{
|
|
187
|
+
className: "border-border text-muted-foreground border-e px-2 py-1.5 text-center text-xs last:border-e-0",
|
|
188
|
+
children: column.setLocale(locale ?? column.locale ?? "en").toFormat(CADENCE_FORMAT[cadence])
|
|
189
|
+
},
|
|
190
|
+
column.toISO()
|
|
191
|
+
))
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
lanes.map((lane) => /* @__PURE__ */ jsxs("section", { children: [
|
|
195
|
+
lane.label && /* @__PURE__ */ jsx(Heading, { children: /* @__PURE__ */ jsx(
|
|
196
|
+
"span",
|
|
197
|
+
{
|
|
198
|
+
"data-slot": "gantt-view-group-label",
|
|
199
|
+
className: cn(
|
|
200
|
+
"border-border bg-muted text-muted-foreground block border-b px-3 py-1.5 text-xs font-semibold tracking-wide uppercase",
|
|
201
|
+
classNames?.groupLabel
|
|
202
|
+
),
|
|
203
|
+
children: lane.label
|
|
204
|
+
}
|
|
205
|
+
) }),
|
|
206
|
+
/* @__PURE__ */ jsx("ul", { children: lane.bars.map((bar) => {
|
|
207
|
+
const accent = accessors.getAccent?.(bar.item) ?? "primary";
|
|
208
|
+
const selected = bar.id === selectedId;
|
|
209
|
+
const title = accessors.getTitle(bar.item);
|
|
210
|
+
const body = renderItem?.(bar.item, { view: "gantt" }) ?? /* @__PURE__ */ jsx("span", { className: "block truncate px-2 text-xs font-medium", children: title });
|
|
211
|
+
const classes = cn(
|
|
212
|
+
"flex h-6 items-center rounded-full border text-foreground",
|
|
213
|
+
accentClasses[accent].tint,
|
|
214
|
+
accentClasses[accent].border,
|
|
215
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
216
|
+
classNames?.bar,
|
|
217
|
+
selected && cn("ring-2 ring-primary-500/50", classNames?.selectedBar)
|
|
218
|
+
);
|
|
219
|
+
const href = getHref?.(bar.id, bar.item);
|
|
220
|
+
return /* @__PURE__ */ jsxs(
|
|
221
|
+
"li",
|
|
222
|
+
{
|
|
223
|
+
"data-slot": "gantt-view-row",
|
|
224
|
+
className: cn(
|
|
225
|
+
"border-border relative grid items-center border-b py-1 last:border-b-0",
|
|
226
|
+
classNames?.row
|
|
227
|
+
),
|
|
228
|
+
style: gridTemplate,
|
|
229
|
+
children: [
|
|
230
|
+
showToday && /* @__PURE__ */ jsx(
|
|
231
|
+
"span",
|
|
232
|
+
{
|
|
233
|
+
"aria-hidden": true,
|
|
234
|
+
className: "bg-primary-500/60 pointer-events-none absolute inset-y-0 w-px",
|
|
235
|
+
style: {
|
|
236
|
+
gridColumn: `${todayColumn} / span 1`,
|
|
237
|
+
insetInlineStart: 0
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
),
|
|
241
|
+
/* @__PURE__ */ jsx(
|
|
242
|
+
"div",
|
|
243
|
+
{
|
|
244
|
+
className: "min-w-0",
|
|
245
|
+
style: {
|
|
246
|
+
gridColumn: `${bar.column} / span ${bar.span}`
|
|
247
|
+
},
|
|
248
|
+
children: href ? /* @__PURE__ */ jsx(
|
|
249
|
+
"a",
|
|
250
|
+
{
|
|
251
|
+
href,
|
|
252
|
+
"aria-current": selected ? "true" : void 0,
|
|
253
|
+
"data-slot": "gantt-view-bar",
|
|
254
|
+
className: classes,
|
|
255
|
+
onClick: (event) => {
|
|
256
|
+
if (!onOpen || event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0)
|
|
257
|
+
return;
|
|
258
|
+
event.preventDefault();
|
|
259
|
+
onOpen(bar.id, bar.item);
|
|
260
|
+
},
|
|
261
|
+
children: body
|
|
262
|
+
}
|
|
263
|
+
) : onOpen ? /* @__PURE__ */ jsx(
|
|
264
|
+
"button",
|
|
265
|
+
{
|
|
266
|
+
type: "button",
|
|
267
|
+
"aria-current": selected ? "true" : void 0,
|
|
268
|
+
"data-slot": "gantt-view-bar",
|
|
269
|
+
className: cn(classes, "w-full text-start"),
|
|
270
|
+
onClick: () => onOpen(bar.id, bar.item),
|
|
271
|
+
children: body
|
|
272
|
+
}
|
|
273
|
+
) : /* @__PURE__ */ jsx("span", { "data-slot": "gantt-view-bar", className: classes, children: body })
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
bar.id
|
|
279
|
+
);
|
|
280
|
+
}) })
|
|
281
|
+
] }, lane.id))
|
|
282
|
+
] })
|
|
283
|
+
}
|
|
284
|
+
),
|
|
285
|
+
undatedCount > 0 && /* @__PURE__ */ jsx(
|
|
286
|
+
"p",
|
|
287
|
+
{
|
|
288
|
+
"data-slot": "gantt-view-undated",
|
|
289
|
+
className: "border-border text-muted-foreground border-t px-3 py-1.5 text-xs",
|
|
290
|
+
children: text.undated.replace("{count}", String(undatedCount))
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export { GanttView, defaultGanttLabels };
|
|
299
|
+
//# sourceMappingURL=chunk-Y4QNLW7W.js.map
|
|
300
|
+
//# sourceMappingURL=chunk-Y4QNLW7W.js.map
|