hs-uix 2.1.0 → 2.2.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.md +3 -1
- package/common-components.d.ts +319 -68
- package/dist/calendar.js +397 -119
- package/dist/calendar.mjs +399 -119
- package/dist/common-components.js +3546 -88
- package/dist/common-components.mjs +3530 -84
- package/dist/datatable.js +108 -18
- package/dist/datatable.mjs +108 -18
- package/dist/experimental.js +2876 -0
- package/dist/experimental.mjs +2883 -0
- package/dist/feed.js +267 -38
- package/dist/feed.mjs +260 -37
- package/dist/filter.js +1379 -0
- package/dist/filter.mjs +1334 -0
- package/dist/form.js +222 -26
- package/dist/form.mjs +227 -27
- package/dist/index.js +3255 -353
- package/dist/index.mjs +3199 -344
- package/dist/kanban.js +282 -62
- package/dist/kanban.mjs +273 -61
- package/dist/safe.js +9207 -0
- package/dist/safe.mjs +9298 -0
- package/dist/utils.js +491 -75
- package/dist/utils.mjs +491 -75
- package/experimental.d.ts +1 -0
- package/filter.d.ts +1 -0
- package/index.d.ts +45 -3
- package/package.json +19 -1
- package/safe.d.ts +1 -0
- package/src/calendar/README.md +76 -5
- package/src/calendar/index.d.ts +108 -1
- package/src/common-components/README.md +140 -1
- package/src/datatable/README.md +0 -2
- package/src/experimental/README.md +126 -0
- package/src/experimental/index.d.ts +346 -0
- package/src/feed/README.md +69 -0
- package/src/feed/index.d.ts +103 -0
- package/src/filter/README.md +148 -0
- package/src/filter/index.d.ts +221 -0
- package/src/form/README.md +132 -4
- package/src/form/index.d.ts +82 -1
- package/src/kanban/README.md +119 -6
- package/src/kanban/index.d.ts +153 -2
- package/src/safe/README.md +108 -0
- package/src/safe/index.d.ts +158 -0
- package/src/utils/README.md +39 -0
- package/src/wizard/README.md +158 -0
- package/src/wizard/index.d.ts +138 -0
- package/utils.d.ts +17 -0
package/dist/kanban.mjs
CHANGED
|
@@ -167,6 +167,109 @@ var useSelectionReset = ({ resetKey, enabled, isControlled, clearSelection }) =>
|
|
|
167
167
|
}, [resetKey, enabled, isControlled, clearSelection]);
|
|
168
168
|
};
|
|
169
169
|
|
|
170
|
+
// src/kanban/kanbanLanes.js
|
|
171
|
+
var UNASSIGNED_LANE_KEY = "__unassigned";
|
|
172
|
+
var UNKNOWN_STAGE_KEY = "__unknown";
|
|
173
|
+
var getLaneKey = (row, swimlaneBy) => {
|
|
174
|
+
const raw = typeof swimlaneBy === "function" ? swimlaneBy(row) : row == null ? void 0 : row[swimlaneBy];
|
|
175
|
+
if (raw == null || raw === "") return UNASSIGNED_LANE_KEY;
|
|
176
|
+
return String(raw);
|
|
177
|
+
};
|
|
178
|
+
var orderLaneKeys = (seenKeys, swimlaneOrder) => {
|
|
179
|
+
const seen = Array.isArray(seenKeys) ? seenKeys : [];
|
|
180
|
+
if (!Array.isArray(swimlaneOrder) || swimlaneOrder.length === 0) return [...seen];
|
|
181
|
+
const explicit = [];
|
|
182
|
+
for (const key of swimlaneOrder) {
|
|
183
|
+
const normalized = String(key);
|
|
184
|
+
if (!explicit.includes(normalized)) explicit.push(normalized);
|
|
185
|
+
}
|
|
186
|
+
const rest = seen.filter((key) => !explicit.includes(key));
|
|
187
|
+
return [...explicit, ...rest];
|
|
188
|
+
};
|
|
189
|
+
var partitionLanes = (rows, { swimlaneBy, swimlaneOrder } = {}) => {
|
|
190
|
+
const rowsByLane = {};
|
|
191
|
+
const firstSeen = [];
|
|
192
|
+
for (const row of rows || []) {
|
|
193
|
+
const key = getLaneKey(row, swimlaneBy);
|
|
194
|
+
if (!rowsByLane[key]) {
|
|
195
|
+
rowsByLane[key] = [];
|
|
196
|
+
firstSeen.push(key);
|
|
197
|
+
}
|
|
198
|
+
rowsByLane[key].push(row);
|
|
199
|
+
}
|
|
200
|
+
const laneKeys = orderLaneKeys(firstSeen, swimlaneOrder);
|
|
201
|
+
for (const key of laneKeys) {
|
|
202
|
+
if (!rowsByLane[key]) rowsByLane[key] = [];
|
|
203
|
+
}
|
|
204
|
+
return { laneKeys, rowsByLane };
|
|
205
|
+
};
|
|
206
|
+
var resolveLaneLabel = (laneKey, swimlaneLabels, rows, unassignedLabel) => {
|
|
207
|
+
if (typeof swimlaneLabels === "function") {
|
|
208
|
+
const out = swimlaneLabels(laneKey, rows || []);
|
|
209
|
+
if (out != null) return out;
|
|
210
|
+
} else if (swimlaneLabels && typeof swimlaneLabels === "object") {
|
|
211
|
+
const out = swimlaneLabels[laneKey];
|
|
212
|
+
if (out != null) return out;
|
|
213
|
+
}
|
|
214
|
+
if (laneKey === UNASSIGNED_LANE_KEY) return unassignedLabel || "Unassigned";
|
|
215
|
+
return String(laneKey);
|
|
216
|
+
};
|
|
217
|
+
var bucketRowsByStage = (rows, stages, getStage) => {
|
|
218
|
+
const map = {};
|
|
219
|
+
for (const stage of stages || []) map[stage.value] = [];
|
|
220
|
+
for (const row of rows || []) {
|
|
221
|
+
const key = getStage(row);
|
|
222
|
+
if (map[key]) {
|
|
223
|
+
map[key].push(row);
|
|
224
|
+
} else if ((stages || []).length > 0) {
|
|
225
|
+
if (!map[UNKNOWN_STAGE_KEY]) map[UNKNOWN_STAGE_KEY] = [];
|
|
226
|
+
map[UNKNOWN_STAGE_KEY].push(row);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return map;
|
|
230
|
+
};
|
|
231
|
+
var sortBuckets = (buckets, comparator) => {
|
|
232
|
+
if (!comparator) return buckets;
|
|
233
|
+
const out = {};
|
|
234
|
+
for (const key of Object.keys(buckets || {})) {
|
|
235
|
+
out[key] = [...buckets[key]].sort(comparator);
|
|
236
|
+
}
|
|
237
|
+
return out;
|
|
238
|
+
};
|
|
239
|
+
var resolveWipLimit = (stage, wipLimits) => {
|
|
240
|
+
const override = wipLimits ? wipLimits[stage == null ? void 0 : stage.value] : void 0;
|
|
241
|
+
const limit = override != null ? override : stage == null ? void 0 : stage.wipLimit;
|
|
242
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit < 0) return null;
|
|
243
|
+
return limit;
|
|
244
|
+
};
|
|
245
|
+
var computeStageCounts = (stages, buckets, stageMeta) => {
|
|
246
|
+
const counts = {};
|
|
247
|
+
for (const stage of stages || []) {
|
|
248
|
+
const meta = stageMeta ? stageMeta[stage.value] : void 0;
|
|
249
|
+
counts[stage.value] = meta && meta.totalCount != null ? meta.totalCount : ((buckets == null ? void 0 : buckets[stage.value]) || []).length;
|
|
250
|
+
}
|
|
251
|
+
return counts;
|
|
252
|
+
};
|
|
253
|
+
var evaluateWip = (stages, counts, wipLimits) => {
|
|
254
|
+
const out = {};
|
|
255
|
+
for (const stage of stages || []) {
|
|
256
|
+
const limit = resolveWipLimit(stage, wipLimits);
|
|
257
|
+
const count = (counts == null ? void 0 : counts[stage.value]) || 0;
|
|
258
|
+
out[stage.value] = { count, limit, exceeded: limit != null && count > limit };
|
|
259
|
+
}
|
|
260
|
+
return out;
|
|
261
|
+
};
|
|
262
|
+
var findNewlyExceededWip = (prev, next) => {
|
|
263
|
+
const events = [];
|
|
264
|
+
for (const stageId of Object.keys(next || {})) {
|
|
265
|
+
const entry = next[stageId];
|
|
266
|
+
if (!entry || !entry.exceeded) continue;
|
|
267
|
+
if (prev && prev[stageId] && prev[stageId].exceeded) continue;
|
|
268
|
+
events.push({ stageId, count: entry.count, limit: entry.limit });
|
|
269
|
+
}
|
|
270
|
+
return events;
|
|
271
|
+
};
|
|
272
|
+
|
|
170
273
|
// src/common-components/CollectionSortSelect.js
|
|
171
274
|
import React, { useId } from "react";
|
|
172
275
|
import { Select } from "@hubspot/ui-extensions";
|
|
@@ -526,7 +629,7 @@ var GENERATED_ICONS = {
|
|
|
526
629
|
"ZoomOut": { "viewBox": "0 0 32 32", "paths": ["M14.42 26.75c2.85 0 5.47-.97 7.56-2.6l-.03.02 5.28 5.34a1.619 1.619 0 0 0 2.76-1.15c0-.45-.18-.85-.47-1.14l-5.33-5.33c1.59-2.06 2.55-4.68 2.55-7.52C26.74 7.54 21.2 2 14.37 2S2 7.55 2 14.38s5.54 12.37 12.37 12.37h.05m0-21.55c5.06 0 9.16 4.1 9.16 9.16s-4.1 9.16-9.16 9.16-9.16-4.1-9.16-9.16c.01-5.05 4.11-9.14 9.16-9.15Zm-4.31 10.78h8.62c.89 0 1.62-.72 1.62-1.62s-.72-1.62-1.62-1.62h-8.62c-.89 0-1.62.72-1.62 1.62s.72 1.62 1.62 1.62"] }
|
|
527
630
|
};
|
|
528
631
|
|
|
529
|
-
// src/common-components/
|
|
632
|
+
// src/common-components/nativeIconNames.js
|
|
530
633
|
var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
531
634
|
"add",
|
|
532
635
|
"appointment",
|
|
@@ -538,12 +641,12 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
|
538
641
|
"block",
|
|
539
642
|
"book",
|
|
540
643
|
"bulb",
|
|
644
|
+
"callTranscript",
|
|
541
645
|
"calling",
|
|
542
646
|
"callingHangup",
|
|
543
647
|
"callingMade",
|
|
544
648
|
"callingMissed",
|
|
545
649
|
"callingVoicemail",
|
|
546
|
-
"callTranscript",
|
|
547
650
|
"campaigns",
|
|
548
651
|
"cap",
|
|
549
652
|
"checkCircle",
|
|
@@ -572,13 +675,13 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
|
572
675
|
"enroll",
|
|
573
676
|
"exclamation",
|
|
574
677
|
"exclamationCircle",
|
|
575
|
-
"facebook",
|
|
576
678
|
"faceHappy",
|
|
577
679
|
"faceHappyFilled",
|
|
578
680
|
"faceNeutral",
|
|
579
681
|
"faceNeutralFilled",
|
|
580
682
|
"faceSad",
|
|
581
683
|
"faceSadFilled",
|
|
684
|
+
"facebook",
|
|
582
685
|
"favoriteHollow",
|
|
583
686
|
"file",
|
|
584
687
|
"filledXCircleIcon",
|
|
@@ -719,6 +822,8 @@ var NATIVE_ICON_NAMES = /* @__PURE__ */ new Set([
|
|
|
719
822
|
"zoomIn",
|
|
720
823
|
"zoomOut"
|
|
721
824
|
]);
|
|
825
|
+
|
|
826
|
+
// src/common-components/Icon.js
|
|
722
827
|
var NATIVE_COLORS = /* @__PURE__ */ new Set(["inherit", "alert", "warning", "success"]);
|
|
723
828
|
var NATIVE_SIZE_TOKENS = {
|
|
724
829
|
sm: "sm",
|
|
@@ -931,6 +1036,7 @@ var CollectionFilterControl = ({
|
|
|
931
1036
|
{ key: name, direction: "row", align: "center", gap: "xs" },
|
|
932
1037
|
h3(DateInput, {
|
|
933
1038
|
name: `${controlName}-from`,
|
|
1039
|
+
label: filter.fromLabel ?? labels.dateFrom,
|
|
934
1040
|
placeholder: filter.fromLabel ?? labels.dateFrom,
|
|
935
1041
|
format: "medium",
|
|
936
1042
|
value: rangeValue.from ?? null,
|
|
@@ -939,6 +1045,7 @@ var CollectionFilterControl = ({
|
|
|
939
1045
|
h3(Icon, { name: "right", size: "sm" }),
|
|
940
1046
|
h3(DateInput, {
|
|
941
1047
|
name: `${controlName}-to`,
|
|
1048
|
+
label: filter.toLabel ?? labels.dateTo,
|
|
942
1049
|
placeholder: filter.toLabel ?? labels.dateTo,
|
|
943
1050
|
format: "medium",
|
|
944
1051
|
value: rangeValue.to ?? null,
|
|
@@ -1269,6 +1376,7 @@ import {
|
|
|
1269
1376
|
Statistics,
|
|
1270
1377
|
StatisticsItem,
|
|
1271
1378
|
StatisticsTrend,
|
|
1379
|
+
StatusTag,
|
|
1272
1380
|
Tag as Tag3,
|
|
1273
1381
|
Text,
|
|
1274
1382
|
Tile
|
|
@@ -1306,6 +1414,12 @@ var DEFAULT_LABELS3 = {
|
|
|
1306
1414
|
errorTitle: "Something went wrong.",
|
|
1307
1415
|
errorMessage: "An error occurred while loading data.",
|
|
1308
1416
|
cardCount: (n) => String(n),
|
|
1417
|
+
// "5 / 4" — count vs WIP limit in the stage header. The slash format is the
|
|
1418
|
+
// standard kanban convention; override for tighter ("5/4") or verbose forms.
|
|
1419
|
+
wipCount: (count, limit) => `${count} / ${limit}`,
|
|
1420
|
+
overWip: "Over WIP",
|
|
1421
|
+
laneCount: (n) => String(n),
|
|
1422
|
+
unassignedLane: "Unassigned",
|
|
1309
1423
|
moveTo: "Move",
|
|
1310
1424
|
clearAll: "Clear all",
|
|
1311
1425
|
selectAll: (count, label) => `Select all ${count} ${label}`,
|
|
@@ -1532,10 +1646,14 @@ var KanbanColumn = ({
|
|
|
1532
1646
|
onToggleCollapsed,
|
|
1533
1647
|
columnFooter,
|
|
1534
1648
|
countDisplay,
|
|
1649
|
+
wip,
|
|
1650
|
+
compactEmpty,
|
|
1535
1651
|
labels,
|
|
1536
1652
|
children
|
|
1537
1653
|
}) => {
|
|
1538
|
-
const
|
|
1654
|
+
const hasWipLimit = wip != null && wip.limit != null;
|
|
1655
|
+
const countLabel = hasWipLimit ? labels.wipCount(wip.count, wip.limit) : labels.cardCount(totalCount != null ? totalCount : bucketCount);
|
|
1656
|
+
const overWipNode = wip && wip.exceeded ? /* @__PURE__ */ React7.createElement(StatusTag, { variant: "warning" }, labels.overWip) : null;
|
|
1539
1657
|
const countNode = countDisplay === "text" ? /* @__PURE__ */ React7.createElement(Text, { format: { fontWeight: "demibold" } }, countLabel) : countDisplay === "none" ? null : /* @__PURE__ */ React7.createElement(Tag3, { variant: "default" }, countLabel);
|
|
1540
1658
|
if (collapsed) {
|
|
1541
1659
|
const rotated = makeRotatedLabelDataUri(stage.label);
|
|
@@ -1568,8 +1686,11 @@ var KanbanColumn = ({
|
|
|
1568
1686
|
}
|
|
1569
1687
|
) : null));
|
|
1570
1688
|
}
|
|
1689
|
+
if (compactEmpty && !loading && rows.length === 0 && bucketCount === 0) {
|
|
1690
|
+
return /* @__PURE__ */ React7.createElement(Tile, { compact: true }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", align: "center", justify: "between", gap: "xs" }, /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy", format: { fontWeight: "demibold" } }, stage.shortLabel || stage.label), /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy", format: { italic: true } }, labels.emptyColumn)));
|
|
1691
|
+
}
|
|
1571
1692
|
const footerContent = stage.footer ? stage.footer(rows) : columnFooter ? columnFooter(rows, stage) : null;
|
|
1572
|
-
return /* @__PURE__ */ React7.createElement(Tile, { compact: true }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "column", gap: "xs" }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", align: "center", justify: "between", gap: "xs" }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ React7.createElement(Text, { format: { fontWeight: "demibold" } }, stage.shortLabel || stage.label), countNode, loading ? /* @__PURE__ */ React7.createElement(LoadingSpinner, { size: "xs" }) : null), /* @__PURE__ */ React7.createElement(Button3, { variant: "transparent", size: "sm", onClick: onToggleCollapsed, tooltip: "Collapse" }, /* @__PURE__ */ React7.createElement(Icon, { name: "left", size: "sm", screenReaderText: `Collapse ${stage.label}` }))), footerContent ? /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy" }, footerContent) : null, /* @__PURE__ */ React7.createElement(Divider, null), children, error ? /* @__PURE__ */ React7.createElement(Alert, { variant: "danger", title: labels.errorTitle }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", gap: "xs", align: "center" }, /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy" }, error), onLoadMore ? /* @__PURE__ */ React7.createElement(Button3, { variant: "transparent", size: "xs", onClick: () => onLoadMore(stage.value) }, labels.retryLoadMore) : null)) : null, !error && hasMore && onLoadMore && !loading && bucketCount > 0 ? /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", justify: "center" }, /* @__PURE__ */ React7.createElement(Link2, { onClick: () => onLoadMore(stage.value) }, labels.loadMore(bucketCount, totalCount))) : null, !error && loading && hasMore ? /* @__PURE__ */ React7.createElement(LoadingSpinner, { size: "sm", layout: "centered", label: labels.loadingMore }) : null, !error && !hasMore && bucketCount > rows.length ? /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", justify: "center" }, /* @__PURE__ */ React7.createElement(Link2, { onClick: onToggleExpanded }, expanded ? labels.showLess : labels.showMore(rows.length, bucketCount))) : null, rows.length === 0 && bucketCount === 0 && !loading ? /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy", format: { italic: true } }, labels.emptyColumn) : null));
|
|
1693
|
+
return /* @__PURE__ */ React7.createElement(Tile, { compact: true }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "column", gap: "xs" }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", align: "center", justify: "between", gap: "xs" }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", align: "center", gap: "xs" }, /* @__PURE__ */ React7.createElement(Text, { format: { fontWeight: "demibold" } }, stage.shortLabel || stage.label), countNode, overWipNode, loading ? /* @__PURE__ */ React7.createElement(LoadingSpinner, { size: "xs" }) : null), /* @__PURE__ */ React7.createElement(Button3, { variant: "transparent", size: "sm", onClick: onToggleCollapsed, tooltip: "Collapse" }, /* @__PURE__ */ React7.createElement(Icon, { name: "left", size: "sm", screenReaderText: `Collapse ${stage.label}` }))), footerContent ? /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy" }, footerContent) : null, /* @__PURE__ */ React7.createElement(Divider, null), children, error ? /* @__PURE__ */ React7.createElement(Alert, { variant: "danger", title: labels.errorTitle }, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", gap: "xs", align: "center" }, /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy" }, error), onLoadMore ? /* @__PURE__ */ React7.createElement(Button3, { variant: "transparent", size: "xs", onClick: () => onLoadMore(stage.value) }, labels.retryLoadMore) : null)) : null, !error && hasMore && onLoadMore && !loading && bucketCount > 0 ? /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", justify: "center" }, /* @__PURE__ */ React7.createElement(Link2, { onClick: () => onLoadMore(stage.value) }, labels.loadMore(bucketCount, totalCount))) : null, !error && loading && hasMore ? /* @__PURE__ */ React7.createElement(LoadingSpinner, { size: "sm", layout: "centered", label: labels.loadingMore }) : null, !error && !hasMore && bucketCount > rows.length ? /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", justify: "center" }, /* @__PURE__ */ React7.createElement(Link2, { onClick: onToggleExpanded }, expanded ? labels.showLess : labels.showMore(rows.length, bucketCount))) : null, rows.length === 0 && bucketCount === 0 && !loading ? /* @__PURE__ */ React7.createElement(Text, { variant: "microcopy", format: { italic: true } }, labels.emptyColumn) : null));
|
|
1573
1694
|
};
|
|
1574
1695
|
var renderMetricsPanel = (metrics) => {
|
|
1575
1696
|
if (!metrics) return null;
|
|
@@ -1608,14 +1729,14 @@ var KanbanToolbar = ({
|
|
|
1608
1729
|
sortOptions,
|
|
1609
1730
|
sortValue,
|
|
1610
1731
|
onSortChange,
|
|
1611
|
-
|
|
1612
|
-
|
|
1732
|
+
showMetricsButton,
|
|
1733
|
+
metricsPanel,
|
|
1613
1734
|
onToggleMetrics,
|
|
1614
1735
|
labels,
|
|
1615
1736
|
toolbarLeftFlex,
|
|
1616
1737
|
toolbarRightFlex
|
|
1617
1738
|
}) => {
|
|
1618
|
-
const rightControls = (sortOptions == null ? void 0 : sortOptions.length) > 0 ||
|
|
1739
|
+
const rightControls = (sortOptions == null ? void 0 : sortOptions.length) > 0 || showMetricsButton ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, sortOptions && sortOptions.length > 0 ? /* @__PURE__ */ React7.createElement(
|
|
1619
1740
|
CollectionSortSelect,
|
|
1620
1741
|
{
|
|
1621
1742
|
name: "kanban-sort",
|
|
@@ -1624,7 +1745,7 @@ var KanbanToolbar = ({
|
|
|
1624
1745
|
options: sortOptions,
|
|
1625
1746
|
onChange: onSortChange
|
|
1626
1747
|
}
|
|
1627
|
-
) : null,
|
|
1748
|
+
) : null, showMetricsButton ? /* @__PURE__ */ React7.createElement(Button3, { variant: "secondary", size: "small", onClick: onToggleMetrics }, /* @__PURE__ */ React7.createElement(Icon, { name: "gauge", size: "sm" }), " ", labels.metricsButton) : null) : null;
|
|
1628
1749
|
return /* @__PURE__ */ React7.createElement(
|
|
1629
1750
|
CollectionToolbar,
|
|
1630
1751
|
{
|
|
@@ -1651,7 +1772,7 @@ var KanbanToolbar = ({
|
|
|
1651
1772
|
onRemove: onFilterRemove
|
|
1652
1773
|
},
|
|
1653
1774
|
right: rightControls,
|
|
1654
|
-
footer:
|
|
1775
|
+
footer: metricsPanel,
|
|
1655
1776
|
labels,
|
|
1656
1777
|
leftFlex: toolbarLeftFlex,
|
|
1657
1778
|
rightFlex: toolbarRightFlex
|
|
@@ -1703,6 +1824,18 @@ var Kanban = ({
|
|
|
1703
1824
|
// --- Per-stage pagination ---
|
|
1704
1825
|
stageMeta,
|
|
1705
1826
|
onLoadMore,
|
|
1827
|
+
// --- WIP limits ---
|
|
1828
|
+
wipLimits,
|
|
1829
|
+
onWipExceeded,
|
|
1830
|
+
// --- Swimlanes ---
|
|
1831
|
+
swimlaneBy,
|
|
1832
|
+
swimlaneLabels,
|
|
1833
|
+
swimlaneOrder,
|
|
1834
|
+
collapseLanes = true,
|
|
1835
|
+
collapsedLanes,
|
|
1836
|
+
defaultCollapsedLanes,
|
|
1837
|
+
onCollapsedLanesChange,
|
|
1838
|
+
metricsPerLane = false,
|
|
1706
1839
|
// --- Selection ---
|
|
1707
1840
|
selectable = false,
|
|
1708
1841
|
selectedIds,
|
|
@@ -1767,6 +1900,9 @@ var Kanban = ({
|
|
|
1767
1900
|
const [internalFilters, setInternalFilters] = useState2(() => getEmptyFilterValues(filters));
|
|
1768
1901
|
const [internalSort, setInternalSort] = useState2(defaultSort || (((_a = sortOptions == null ? void 0 : sortOptions[0]) == null ? void 0 : _a.value) ?? ""));
|
|
1769
1902
|
const [internalCollapsed, setInternalCollapsed] = useState2([]);
|
|
1903
|
+
const [internalCollapsedLanes, setInternalCollapsedLanes] = useState2(
|
|
1904
|
+
() => defaultCollapsedLanes || []
|
|
1905
|
+
);
|
|
1770
1906
|
const [internalExpanded, setInternalExpanded] = useState2([]);
|
|
1771
1907
|
const [internalSelection, setInternalSelection] = useState2([]);
|
|
1772
1908
|
const [internalShowMetrics, setInternalShowMetrics] = useState2(false);
|
|
@@ -1783,6 +1919,7 @@ var Kanban = ({
|
|
|
1783
1919
|
const resolvedFilters = filterValues != null ? filterValues : internalFilters;
|
|
1784
1920
|
const resolvedSort = sort != null ? sort : internalSort;
|
|
1785
1921
|
const resolvedCollapsed = collapsedStages != null ? collapsedStages : internalCollapsed;
|
|
1922
|
+
const resolvedCollapsedLanes = collapsedLanes != null ? collapsedLanes : internalCollapsedLanes;
|
|
1786
1923
|
const resolvedExpanded = expandedStages != null ? expandedStages : internalExpanded;
|
|
1787
1924
|
const resolvedSelection = selectedIds != null ? selectedIds : internalSelection;
|
|
1788
1925
|
const searchEnabled = showSearch && Array.isArray(searchFields) && searchFields.length > 0;
|
|
@@ -1799,9 +1936,10 @@ var Kanban = ({
|
|
|
1799
1936
|
search: overrides.search != null ? overrides.search : resolvedSearch,
|
|
1800
1937
|
filters: overrides.filters != null ? overrides.filters : resolvedFilters,
|
|
1801
1938
|
sort: overrides.sort != null ? overrides.sort : resolvedSort || null,
|
|
1802
|
-
collapsedStages: overrides.collapsedStages != null ? overrides.collapsedStages : resolvedCollapsed
|
|
1939
|
+
collapsedStages: overrides.collapsedStages != null ? overrides.collapsedStages : resolvedCollapsed,
|
|
1940
|
+
collapsedLanes: overrides.collapsedLanes != null ? overrides.collapsedLanes : resolvedCollapsedLanes
|
|
1803
1941
|
});
|
|
1804
|
-
}, [onParamsChange, resolvedCollapsed, resolvedFilters, resolvedSearch, resolvedSort]);
|
|
1942
|
+
}, [onParamsChange, resolvedCollapsed, resolvedCollapsedLanes, resolvedFilters, resolvedSearch, resolvedSort]);
|
|
1805
1943
|
const lastAppliedSearchRef = useRef2(searchValue != null ? searchValue : "");
|
|
1806
1944
|
useEffect2(() => {
|
|
1807
1945
|
if (searchValue == null) return;
|
|
@@ -1860,6 +1998,15 @@ var Kanban = ({
|
|
|
1860
1998
|
},
|
|
1861
1999
|
[fireParamsChange, resolvedCollapsed, collapsedStages, onCollapsedStagesChange]
|
|
1862
2000
|
);
|
|
2001
|
+
const handleLaneCollapsed = useCallback2(
|
|
2002
|
+
(laneKey) => {
|
|
2003
|
+
const next = resolvedCollapsedLanes.includes(laneKey) ? resolvedCollapsedLanes.filter((k) => k !== laneKey) : [...resolvedCollapsedLanes, laneKey];
|
|
2004
|
+
if (onCollapsedLanesChange) onCollapsedLanesChange(next);
|
|
2005
|
+
if (collapsedLanes == null) setInternalCollapsedLanes(next);
|
|
2006
|
+
fireParamsChange({ collapsedLanes: next });
|
|
2007
|
+
},
|
|
2008
|
+
[fireParamsChange, resolvedCollapsedLanes, collapsedLanes, onCollapsedLanesChange]
|
|
2009
|
+
);
|
|
1863
2010
|
const handleExpanded = useCallback2(
|
|
1864
2011
|
(stageValue) => {
|
|
1865
2012
|
const next = resolvedExpanded.includes(stageValue) ? resolvedExpanded.filter((v) => v !== stageValue) : [...resolvedExpanded, stageValue];
|
|
@@ -1928,33 +2075,45 @@ var Kanban = ({
|
|
|
1928
2075
|
}
|
|
1929
2076
|
return result;
|
|
1930
2077
|
}, [data, resolvedSearch, resolvedFilters, filters, searchEnabled, searchFields, fuzzySearch, fuzzyOptions]);
|
|
1931
|
-
const buckets = useMemo(
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
const key = getStageFor(row);
|
|
1936
|
-
if (map[key]) {
|
|
1937
|
-
map[key].push(row);
|
|
1938
|
-
} else if (stages.length > 0) {
|
|
1939
|
-
if (!map.__unknown) map.__unknown = [];
|
|
1940
|
-
map.__unknown.push(row);
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
return map;
|
|
1944
|
-
}, [filteredData, stages, getStageFor]);
|
|
2078
|
+
const buckets = useMemo(
|
|
2079
|
+
() => bucketRowsByStage(filteredData, stages, getStageFor),
|
|
2080
|
+
[filteredData, stages, getStageFor]
|
|
2081
|
+
);
|
|
1945
2082
|
const sortComparator = useMemo(() => {
|
|
1946
2083
|
if (!sortOptions || !resolvedSort) return null;
|
|
1947
2084
|
const opt = sortOptions.find((s) => s.value === resolvedSort);
|
|
1948
2085
|
return (opt == null ? void 0 : opt.comparator) || null;
|
|
1949
2086
|
}, [sortOptions, resolvedSort]);
|
|
1950
|
-
const sortedBuckets = useMemo(() =>
|
|
1951
|
-
|
|
2087
|
+
const sortedBuckets = useMemo(() => sortBuckets(buckets, sortComparator), [buckets, sortComparator]);
|
|
2088
|
+
const hasLanes = swimlaneBy != null;
|
|
2089
|
+
const laneData = useMemo(() => {
|
|
2090
|
+
if (!hasLanes) return null;
|
|
2091
|
+
return partitionLanes(filteredData, { swimlaneBy, swimlaneOrder });
|
|
2092
|
+
}, [hasLanes, filteredData, swimlaneBy, swimlaneOrder]);
|
|
2093
|
+
const laneBuckets = useMemo(() => {
|
|
2094
|
+
if (!laneData) return null;
|
|
1952
2095
|
const out = {};
|
|
1953
|
-
for (const
|
|
1954
|
-
out[
|
|
2096
|
+
for (const laneKey of laneData.laneKeys) {
|
|
2097
|
+
out[laneKey] = sortBuckets(
|
|
2098
|
+
bucketRowsByStage(laneData.rowsByLane[laneKey] || [], stages, getStageFor),
|
|
2099
|
+
sortComparator
|
|
2100
|
+
);
|
|
1955
2101
|
}
|
|
1956
2102
|
return out;
|
|
1957
|
-
}, [
|
|
2103
|
+
}, [laneData, stages, getStageFor, sortComparator]);
|
|
2104
|
+
const wipByStage = useMemo(
|
|
2105
|
+
() => evaluateWip(stages, computeStageCounts(stages, buckets, stageMeta), wipLimits),
|
|
2106
|
+
[stages, buckets, stageMeta, wipLimits]
|
|
2107
|
+
);
|
|
2108
|
+
const prevWipRef = useRef2({});
|
|
2109
|
+
useEffect2(() => {
|
|
2110
|
+
const newlyExceeded = findNewlyExceededWip(prevWipRef.current, wipByStage);
|
|
2111
|
+
prevWipRef.current = wipByStage;
|
|
2112
|
+
if (!onWipExceeded) return;
|
|
2113
|
+
for (const event of newlyExceeded) {
|
|
2114
|
+
onWipExceeded(event.stageId, event.count, event.limit);
|
|
2115
|
+
}
|
|
2116
|
+
}, [wipByStage, onWipExceeded]);
|
|
1958
2117
|
const activeChips = useMemo(
|
|
1959
2118
|
() => buildActiveFilterChips(filters, resolvedFilters),
|
|
1960
2119
|
[filters, resolvedFilters]
|
|
@@ -2081,6 +2240,52 @@ var Kanban = ({
|
|
|
2081
2240
|
selectionActions: selectionActions || [],
|
|
2082
2241
|
labels
|
|
2083
2242
|
};
|
|
2243
|
+
const metricsProvided = metrics != null && (!Array.isArray(metrics) || metrics.length > 0);
|
|
2244
|
+
const perLaneMetricsActive = hasLanes && metricsPerLane && typeof metrics === "function";
|
|
2245
|
+
const globalMetricsContent = metricsProvided && !perLaneMetricsActive ? typeof metrics === "function" ? metrics(filteredData, null) : metrics : null;
|
|
2246
|
+
const renderStageColumns = (bucketMap, laneKey) => {
|
|
2247
|
+
const inLane = laneKey != null;
|
|
2248
|
+
return /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", gap: "sm", wrap: "nowrap" }, stages.map((stage) => {
|
|
2249
|
+
const stageRows = bucketMap[stage.value] || [];
|
|
2250
|
+
const meta = inLane ? void 0 : stageMeta == null ? void 0 : stageMeta[stage.value];
|
|
2251
|
+
const isExpanded = resolvedExpanded.includes(stage.value);
|
|
2252
|
+
const clamp = isExpanded ? maxCardsExpanded : maxCardsPerColumn;
|
|
2253
|
+
const visibleRows = stageRows.slice(0, clamp);
|
|
2254
|
+
const isCollapsed = resolvedCollapsed.includes(stage.value);
|
|
2255
|
+
const stageWip = wipByStage[stage.value];
|
|
2256
|
+
const wip = inLane ? (stageWip == null ? void 0 : stageWip.exceeded) ? { count: stageWip.count, limit: null, exceeded: true } : null : stageWip;
|
|
2257
|
+
return /* @__PURE__ */ React7.createElement(
|
|
2258
|
+
AutoGrid,
|
|
2259
|
+
{
|
|
2260
|
+
key: inLane ? `${laneKey}::${stage.value}` : stage.value,
|
|
2261
|
+
columnWidth: isCollapsed ? 72 : effectiveColumnWidth
|
|
2262
|
+
},
|
|
2263
|
+
/* @__PURE__ */ React7.createElement(
|
|
2264
|
+
KanbanColumn,
|
|
2265
|
+
{
|
|
2266
|
+
stage,
|
|
2267
|
+
rows: visibleRows,
|
|
2268
|
+
bucketCount: stageRows.length,
|
|
2269
|
+
totalCount: meta == null ? void 0 : meta.totalCount,
|
|
2270
|
+
hasMore: meta == null ? void 0 : meta.hasMore,
|
|
2271
|
+
loading: meta == null ? void 0 : meta.loading,
|
|
2272
|
+
error: meta == null ? void 0 : meta.error,
|
|
2273
|
+
onLoadMore: inLane ? void 0 : onLoadMore,
|
|
2274
|
+
expanded: isExpanded,
|
|
2275
|
+
onToggleExpanded: () => handleExpanded(stage.value),
|
|
2276
|
+
collapsed: isCollapsed,
|
|
2277
|
+
onToggleCollapsed: () => handleCollapsed(stage.value),
|
|
2278
|
+
columnFooter,
|
|
2279
|
+
countDisplay,
|
|
2280
|
+
wip,
|
|
2281
|
+
compactEmpty: inLane,
|
|
2282
|
+
labels
|
|
2283
|
+
},
|
|
2284
|
+
visibleRows.map((row) => renderCardNode(row, stage))
|
|
2285
|
+
)
|
|
2286
|
+
);
|
|
2287
|
+
}));
|
|
2288
|
+
};
|
|
2084
2289
|
const mainContent = error ? renderErrorState ? renderErrorState({
|
|
2085
2290
|
error,
|
|
2086
2291
|
title: labels.errorTitle,
|
|
@@ -2092,35 +2297,32 @@ var Kanban = ({
|
|
|
2092
2297
|
) : filteredData.length === 0 ? renderEmptyState ? renderEmptyState({
|
|
2093
2298
|
title: labels.emptyTitle,
|
|
2094
2299
|
message: labels.emptyMessage
|
|
2095
|
-
}) : /* @__PURE__ */ React7.createElement(Tile, null, /* @__PURE__ */ React7.createElement(Flex4, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ React7.createElement(EmptyState, { title: labels.emptyTitle, layout: "vertical" }, /* @__PURE__ */ React7.createElement(Text, null, labels.emptyMessage)))) : /* @__PURE__ */ React7.createElement(Flex4, { direction: "
|
|
2096
|
-
const
|
|
2097
|
-
const
|
|
2098
|
-
const
|
|
2099
|
-
const
|
|
2100
|
-
const
|
|
2101
|
-
const
|
|
2102
|
-
|
|
2103
|
-
|
|
2300
|
+
}) : /* @__PURE__ */ React7.createElement(Tile, null, /* @__PURE__ */ React7.createElement(Flex4, { direction: "column", align: "center", justify: "center" }, /* @__PURE__ */ React7.createElement(EmptyState, { title: labels.emptyTitle, layout: "vertical" }, /* @__PURE__ */ React7.createElement(Text, null, labels.emptyMessage)))) : hasLanes ? /* @__PURE__ */ React7.createElement(Flex4, { direction: "column", gap: "md" }, ((laneData == null ? void 0 : laneData.laneKeys) || []).map((laneKey, laneIndex) => {
|
|
2301
|
+
const laneRows = laneData.rowsByLane[laneKey] || [];
|
|
2302
|
+
const laneLabel = resolveLaneLabel(laneKey, swimlaneLabels, laneRows, labels.unassignedLane);
|
|
2303
|
+
const laneLabelText = typeof laneLabel === "string" ? laneLabel : String(laneKey);
|
|
2304
|
+
const isLaneCollapsed = collapseLanes && resolvedCollapsedLanes.includes(laneKey);
|
|
2305
|
+
const laneCountLabel = labels.laneCount(laneRows.length);
|
|
2306
|
+
const laneCountNode = countDisplay === "none" ? null : countDisplay === "text" ? /* @__PURE__ */ React7.createElement(Text, { format: { fontWeight: "demibold" } }, laneCountLabel) : /* @__PURE__ */ React7.createElement(Tag3, { variant: "default" }, laneCountLabel);
|
|
2307
|
+
const laneMetricsNode = !isLaneCollapsed && perLaneMetricsActive && resolvedShowMetrics ? renderMetricsPanel(metrics(laneRows, laneKey)) : null;
|
|
2308
|
+
return /* @__PURE__ */ React7.createElement(Flex4, { key: laneKey, direction: "column", gap: "xs" }, laneIndex > 0 ? /* @__PURE__ */ React7.createElement(Divider, null) : null, /* @__PURE__ */ React7.createElement(Flex4, { direction: "row", align: "center", gap: "xs" }, collapseLanes ? /* @__PURE__ */ React7.createElement(
|
|
2309
|
+
Button3,
|
|
2104
2310
|
{
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
hasMore: meta == null ? void 0 : meta.hasMore,
|
|
2110
|
-
loading: meta == null ? void 0 : meta.loading,
|
|
2111
|
-
error: meta == null ? void 0 : meta.error,
|
|
2112
|
-
onLoadMore,
|
|
2113
|
-
expanded: isExpanded,
|
|
2114
|
-
onToggleExpanded: () => handleExpanded(stage.value),
|
|
2115
|
-
collapsed: isCollapsed,
|
|
2116
|
-
onToggleCollapsed: () => handleCollapsed(stage.value),
|
|
2117
|
-
columnFooter,
|
|
2118
|
-
countDisplay,
|
|
2119
|
-
labels
|
|
2311
|
+
variant: "transparent",
|
|
2312
|
+
size: "sm",
|
|
2313
|
+
onClick: () => handleLaneCollapsed(laneKey),
|
|
2314
|
+
tooltip: isLaneCollapsed ? `Expand ${laneLabelText}` : `Collapse ${laneLabelText}`
|
|
2120
2315
|
},
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2316
|
+
/* @__PURE__ */ React7.createElement(
|
|
2317
|
+
Icon,
|
|
2318
|
+
{
|
|
2319
|
+
name: isLaneCollapsed ? "right" : "down",
|
|
2320
|
+
size: "sm",
|
|
2321
|
+
screenReaderText: isLaneCollapsed ? `Expand ${laneLabelText}` : `Collapse ${laneLabelText}`
|
|
2322
|
+
}
|
|
2323
|
+
)
|
|
2324
|
+
) : null, /* @__PURE__ */ React7.createElement(Text, { format: { fontWeight: "demibold" } }, laneLabel), laneCountNode), laneMetricsNode, !isLaneCollapsed ? renderStageColumns((laneBuckets == null ? void 0 : laneBuckets[laneKey]) || {}, laneKey) : null);
|
|
2325
|
+
})) : renderStageColumns(sortedBuckets, null);
|
|
2124
2326
|
const resolvedShowClearFiltersButton = showClearFiltersButton ?? showFilterBadges;
|
|
2125
2327
|
return /* @__PURE__ */ React7.createElement(Flex4, { direction: "column", gap: "sm" }, /* @__PURE__ */ React7.createElement(
|
|
2126
2328
|
KanbanToolbar,
|
|
@@ -2140,8 +2342,8 @@ var Kanban = ({
|
|
|
2140
2342
|
sortOptions,
|
|
2141
2343
|
sortValue: resolvedSort,
|
|
2142
2344
|
onSortChange: handleSort,
|
|
2143
|
-
|
|
2144
|
-
|
|
2345
|
+
showMetricsButton: metricsProvided,
|
|
2346
|
+
metricsPanel: resolvedShowMetrics && globalMetricsContent ? renderMetricsPanel(globalMetricsContent) : null,
|
|
2145
2347
|
onToggleMetrics: toggleMetrics,
|
|
2146
2348
|
labels,
|
|
2147
2349
|
toolbarLeftFlex,
|
|
@@ -2149,6 +2351,7 @@ var Kanban = ({
|
|
|
2149
2351
|
}
|
|
2150
2352
|
), showSelectionBar && selectable && selectedCount > 0 ? renderSelectionBar ? renderSelectionBar(selectionBarProps) : /* @__PURE__ */ React7.createElement(DefaultSelectionBar, { ...selectionBarProps }) : null, mainContent);
|
|
2151
2353
|
};
|
|
2354
|
+
Kanban.displayName = "Kanban";
|
|
2152
2355
|
|
|
2153
2356
|
// src/kanban/KanbanCardActions.jsx
|
|
2154
2357
|
import React8 from "react";
|
|
@@ -2215,5 +2418,14 @@ var KanbanCardActions = ({
|
|
|
2215
2418
|
};
|
|
2216
2419
|
export {
|
|
2217
2420
|
Kanban,
|
|
2218
|
-
KanbanCardActions
|
|
2421
|
+
KanbanCardActions,
|
|
2422
|
+
UNASSIGNED_LANE_KEY,
|
|
2423
|
+
computeStageCounts,
|
|
2424
|
+
evaluateWip,
|
|
2425
|
+
findNewlyExceededWip,
|
|
2426
|
+
getLaneKey,
|
|
2427
|
+
orderLaneKeys,
|
|
2428
|
+
partitionLanes,
|
|
2429
|
+
resolveLaneLabel,
|
|
2430
|
+
resolveWipLimit
|
|
2219
2431
|
};
|