@almadar/ui 3.9.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7872,7 +7872,7 @@ var init_MapView = __esm({
7872
7872
  shadowSize: [41, 41]
7873
7873
  });
7874
7874
  L.Marker.prototype.options.icon = defaultIcon;
7875
- const { useEffect: useEffect62, useRef: useRef62, useCallback: useCallback95, useState: useState87 } = React115__default;
7875
+ const { useEffect: useEffect62, useRef: useRef62, useCallback: useCallback94, useState: useState86 } = React115__default;
7876
7876
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
7877
7877
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
7878
7878
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -7916,8 +7916,8 @@ var init_MapView = __esm({
7916
7916
  showAttribution = true
7917
7917
  }) {
7918
7918
  const eventBus = useEventBus2();
7919
- const [clickedPosition, setClickedPosition] = useState87(null);
7920
- const handleMapClick = useCallback95((lat, lng) => {
7919
+ const [clickedPosition, setClickedPosition] = useState86(null);
7920
+ const handleMapClick = useCallback94((lat, lng) => {
7921
7921
  if (showClickedPin) {
7922
7922
  setClickedPosition({ lat, lng });
7923
7923
  }
@@ -7926,7 +7926,7 @@ var init_MapView = __esm({
7926
7926
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
7927
7927
  }
7928
7928
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
7929
- const handleMarkerClick = useCallback95((marker) => {
7929
+ const handleMarkerClick = useCallback94((marker) => {
7930
7930
  onMarkerClick?.(marker);
7931
7931
  if (markerClickEvent) {
7932
7932
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -18556,7 +18556,290 @@ function formatValue(value, format) {
18556
18556
  return String(value);
18557
18557
  }
18558
18558
  }
18559
- var gapStyles6, DataGrid;
18559
+ function DataGrid({
18560
+ entity,
18561
+ fields: fieldsProp,
18562
+ columns: columnsProp,
18563
+ itemActions,
18564
+ cols,
18565
+ gap = "md",
18566
+ minCardWidth = 280,
18567
+ className,
18568
+ isLoading = false,
18569
+ error = null,
18570
+ imageField,
18571
+ selectable = false,
18572
+ selectionEvent,
18573
+ infiniteScroll,
18574
+ loadMoreEvent,
18575
+ hasMore,
18576
+ children,
18577
+ pageSize = 0
18578
+ }) {
18579
+ const eventBus = useEventBus();
18580
+ const { t } = useTranslate();
18581
+ const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
18582
+ const [visibleCount, setVisibleCount] = useState(pageSize || Infinity);
18583
+ const fields = fieldsProp ?? columnsProp ?? [];
18584
+ const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
18585
+ const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
18586
+ const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
18587
+ const toggleSelection = useCallback((id) => {
18588
+ setSelectedIds((prev) => {
18589
+ const next = new Set(prev);
18590
+ if (next.has(id)) next.delete(id);
18591
+ else next.add(id);
18592
+ if (selectionEvent) {
18593
+ const payload = { selectedIds: Array.from(next) };
18594
+ eventBus.emit(`UI:${selectionEvent}`, payload);
18595
+ }
18596
+ return next;
18597
+ });
18598
+ }, [selectionEvent, eventBus]);
18599
+ const toggleAll = useCallback(() => {
18600
+ setSelectedIds((prev) => {
18601
+ const allIds2 = data.map((item, i) => item.id || String(i));
18602
+ const allSelected2 = allIds2.length > 0 && allIds2.every((id) => prev.has(id));
18603
+ const next = allSelected2 ? /* @__PURE__ */ new Set() : new Set(allIds2);
18604
+ if (selectionEvent) {
18605
+ const payload = { selectedIds: Array.from(next) };
18606
+ eventBus.emit(`UI:${selectionEvent}`, payload);
18607
+ }
18608
+ return next;
18609
+ });
18610
+ }, [data, selectionEvent, eventBus]);
18611
+ const titleField = fields.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fields[0];
18612
+ const badgeFields = fields.filter((f3) => f3.variant === "badge" && f3 !== titleField);
18613
+ const bodyFields = fields.filter((f3) => f3 !== titleField && !badgeFields.includes(f3));
18614
+ const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
18615
+ const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
18616
+ const handleActionClick = (action, itemData) => (e) => {
18617
+ e.stopPropagation();
18618
+ const payload = {
18619
+ id: itemData.id,
18620
+ row: itemData
18621
+ };
18622
+ eventBus.emit(`UI:${action.event}`, payload);
18623
+ };
18624
+ const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
18625
+ const colsClass = cols ? {
18626
+ 1: "grid-cols-1",
18627
+ 2: "sm:grid-cols-2",
18628
+ 3: "sm:grid-cols-2 lg:grid-cols-3",
18629
+ 4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
18630
+ 5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
18631
+ 6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
18632
+ }[cols] : void 0;
18633
+ if (isLoading) {
18634
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
18635
+ }
18636
+ if (error) {
18637
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
18638
+ }
18639
+ if (data.length === 0) {
18640
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18641
+ }
18642
+ const hasRenderProp = typeof children === "function";
18643
+ const allIds = data.map((item, i) => item.id || String(i));
18644
+ const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
18645
+ const someSelected = selectedIds.size > 0;
18646
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
18647
+ selectable && someSelected && /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center px-2 py-2 bg-muted rounded-sm", children: [
18648
+ /* @__PURE__ */ jsx(
18649
+ "input",
18650
+ {
18651
+ type: "checkbox",
18652
+ checked: allSelected,
18653
+ onChange: toggleAll,
18654
+ className: "w-4 h-4 accent-primary",
18655
+ "aria-label": "Select all"
18656
+ }
18657
+ ),
18658
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "font-semibold", children: [
18659
+ selectedIds.size,
18660
+ " ",
18661
+ t("common.selected") || "selected"
18662
+ ] })
18663
+ ] }),
18664
+ /* @__PURE__ */ jsx(
18665
+ Box,
18666
+ {
18667
+ className: cn("grid", gapStyles6[gap], colsClass, className),
18668
+ style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
18669
+ children: data.map((item, index) => {
18670
+ const itemData = item;
18671
+ const id = itemData.id || String(index);
18672
+ const isSelected = selectedIds.has(id);
18673
+ if (hasRenderProp) {
18674
+ return /* @__PURE__ */ jsx(
18675
+ Box,
18676
+ {
18677
+ "data-entity-row": true,
18678
+ "data-entity-id": id,
18679
+ className: cn(
18680
+ "bg-card rounded-lg",
18681
+ "border border-border",
18682
+ "shadow-sm hover:shadow-lg",
18683
+ "hover:border-primary transition-all",
18684
+ "p-4",
18685
+ isSelected && "ring-2 ring-primary border-primary"
18686
+ ),
18687
+ children: children(itemData, index)
18688
+ },
18689
+ id
18690
+ );
18691
+ }
18692
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
18693
+ return /* @__PURE__ */ jsxs(
18694
+ Box,
18695
+ {
18696
+ "data-entity-row": true,
18697
+ "data-entity-id": id,
18698
+ className: cn(
18699
+ "bg-card rounded-lg",
18700
+ "border border-border",
18701
+ "shadow-sm hover:shadow-lg",
18702
+ "hover:border-primary transition-all",
18703
+ "flex flex-col",
18704
+ isSelected && "ring-2 ring-primary border-primary"
18705
+ ),
18706
+ children: [
18707
+ imageField && (() => {
18708
+ const imgUrl = getNestedValue(itemData, imageField);
18709
+ if (!imgUrl || typeof imgUrl !== "string") return null;
18710
+ return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-lg", children: /* @__PURE__ */ jsx(
18711
+ "img",
18712
+ {
18713
+ src: imgUrl,
18714
+ alt: titleValue !== void 0 ? String(titleValue) : "",
18715
+ className: "w-full h-full object-cover",
18716
+ loading: "lazy"
18717
+ }
18718
+ ) });
18719
+ })(),
18720
+ /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
18721
+ selectable && /* @__PURE__ */ jsx(
18722
+ "input",
18723
+ {
18724
+ type: "checkbox",
18725
+ checked: isSelected,
18726
+ onChange: () => toggleSelection(id),
18727
+ onClick: (e) => e.stopPropagation(),
18728
+ className: "w-4 h-4 mt-1 flex-shrink-0 accent-primary",
18729
+ "aria-label": `Select ${titleValue !== void 0 ? String(titleValue) : "item"}`
18730
+ }
18731
+ ),
18732
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
18733
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18734
+ titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-primary flex-shrink-0" }),
18735
+ /* @__PURE__ */ jsx(
18736
+ Typography,
18737
+ {
18738
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
18739
+ className: "font-semibold truncate",
18740
+ children: String(titleValue)
18741
+ }
18742
+ )
18743
+ ] }),
18744
+ badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
18745
+ const val = getNestedValue(itemData, field.name);
18746
+ if (val === void 0 || val === null) return null;
18747
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18748
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
18749
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
18750
+ ] }, field.name);
18751
+ }) })
18752
+ ] }),
18753
+ dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
18754
+ Button,
18755
+ {
18756
+ variant: "ghost",
18757
+ size: "sm",
18758
+ onClick: handleActionClick(action, itemData),
18759
+ "data-testid": `action-${action.event}`,
18760
+ className: "text-error hover:bg-error/10 px-2",
18761
+ children: [
18762
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
18763
+ action.label
18764
+ ]
18765
+ },
18766
+ idx
18767
+ )) })
18768
+ ] }) }),
18769
+ bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
18770
+ const value = getNestedValue(itemData, field.name);
18771
+ if (value === void 0 || value === null || value === "") return null;
18772
+ if (field.format === "boolean") {
18773
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
18774
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18775
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
18776
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
18777
+ ] }),
18778
+ /* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
18779
+ ] }, field.name);
18780
+ }
18781
+ return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
18782
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18783
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
18784
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
18785
+ ] }),
18786
+ /* @__PURE__ */ jsx(
18787
+ Typography,
18788
+ {
18789
+ variant: field.variant === "caption" ? "caption" : "small",
18790
+ className: "text-right truncate max-w-[60%]",
18791
+ children: formatValue(value, field.format)
18792
+ }
18793
+ )
18794
+ ] }, field.name);
18795
+ }) }) }),
18796
+ primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "justify-end", children: primaryActions.map((action, idx) => /* @__PURE__ */ jsxs(
18797
+ Button,
18798
+ {
18799
+ variant: action.variant === "primary" ? "primary" : "ghost",
18800
+ size: "sm",
18801
+ onClick: handleActionClick(action, itemData),
18802
+ "data-testid": `action-${action.event}`,
18803
+ children: [
18804
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
18805
+ action.label
18806
+ ]
18807
+ },
18808
+ idx
18809
+ )) }) })
18810
+ ]
18811
+ },
18812
+ id
18813
+ );
18814
+ })
18815
+ }
18816
+ ),
18817
+ hasMoreLocal && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(
18818
+ Button,
18819
+ {
18820
+ variant: "ghost",
18821
+ size: "sm",
18822
+ onClick: () => setVisibleCount((prev) => prev + (pageSize || 5)),
18823
+ children: [
18824
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
18825
+ t("common.showMore"),
18826
+ " (",
18827
+ allData.length - visibleCount,
18828
+ " remaining)"
18829
+ ]
18830
+ }
18831
+ ) }),
18832
+ infiniteScroll && loadMoreEvent && /* @__PURE__ */ jsx(
18833
+ InfiniteScrollSentinel,
18834
+ {
18835
+ loadMoreEvent,
18836
+ isLoading,
18837
+ hasMore
18838
+ }
18839
+ )
18840
+ ] });
18841
+ }
18842
+ var gapStyles6;
18560
18843
  var init_DataGrid = __esm({
18561
18844
  "components/molecules/DataGrid.tsx"() {
18562
18845
  "use client";
@@ -18578,264 +18861,321 @@ var init_DataGrid = __esm({
18578
18861
  lg: "gap-6",
18579
18862
  xl: "gap-8"
18580
18863
  };
18581
- DataGrid = ({
18582
- entity,
18583
- fields: fieldsProp,
18584
- columns: columnsProp,
18585
- itemActions,
18586
- cols,
18587
- gap = "md",
18588
- minCardWidth = 280,
18589
- className,
18590
- isLoading = false,
18591
- error = null,
18592
- imageField,
18593
- selectable = false,
18594
- selectionEvent,
18595
- infiniteScroll,
18596
- loadMoreEvent,
18597
- hasMore,
18598
- children,
18599
- pageSize = 0
18600
- }) => {
18601
- const eventBus = useEventBus();
18602
- const { t } = useTranslate();
18603
- const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
18604
- const [visibleCount, setVisibleCount] = useState(pageSize || Infinity);
18605
- const fields = fieldsProp ?? columnsProp ?? [];
18606
- const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
18607
- const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
18608
- const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
18609
- const toggleSelection = useCallback((id) => {
18610
- setSelectedIds((prev) => {
18611
- const next = new Set(prev);
18612
- if (next.has(id)) next.delete(id);
18613
- else next.add(id);
18614
- if (selectionEvent) {
18615
- const payload = { selectedIds: Array.from(next) };
18616
- eventBus.emit(`UI:${selectionEvent}`, payload);
18617
- }
18618
- return next;
18619
- });
18620
- }, [selectionEvent, eventBus]);
18621
- const toggleAll = useCallback(() => {
18622
- setSelectedIds((prev) => {
18623
- const allIds2 = data.map((item, i) => item.id || String(i));
18624
- const allSelected2 = allIds2.length > 0 && allIds2.every((id) => prev.has(id));
18625
- const next = allSelected2 ? /* @__PURE__ */ new Set() : new Set(allIds2);
18626
- if (selectionEvent) {
18627
- const payload = { selectedIds: Array.from(next) };
18628
- eventBus.emit(`UI:${selectionEvent}`, payload);
18629
- }
18630
- return next;
18631
- });
18632
- }, [data, selectionEvent, eventBus]);
18633
- const titleField = fields.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fields[0];
18634
- const badgeFields = fields.filter((f3) => f3.variant === "badge" && f3 !== titleField);
18635
- const bodyFields = fields.filter((f3) => f3 !== titleField && !badgeFields.includes(f3));
18636
- const primaryActions = itemActions?.filter((a) => a.variant !== "danger") ?? [];
18637
- const dangerActions = itemActions?.filter((a) => a.variant === "danger") ?? [];
18638
- const handleActionClick = (action, itemData) => (e) => {
18639
- e.stopPropagation();
18640
- const payload = {
18641
- id: itemData.id,
18642
- row: itemData
18643
- };
18644
- eventBus.emit(`UI:${action.event}`, payload);
18645
- };
18646
- const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
18647
- const colsClass = cols ? {
18648
- 1: "grid-cols-1",
18649
- 2: "sm:grid-cols-2",
18650
- 3: "sm:grid-cols-2 lg:grid-cols-3",
18651
- 4: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
18652
- 5: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
18653
- 6: "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
18654
- }[cols] : void 0;
18655
- if (isLoading) {
18656
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
18657
- }
18658
- if (error) {
18659
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
18660
- }
18661
- if (data.length === 0) {
18662
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18663
- }
18664
- const hasRenderProp = typeof children === "function";
18665
- const allIds = data.map((item, i) => item.id || String(i));
18666
- const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
18667
- const someSelected = selectedIds.size > 0;
18668
- return /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
18669
- selectable && someSelected && /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center px-2 py-2 bg-muted rounded-sm", children: [
18670
- /* @__PURE__ */ jsx(
18671
- "input",
18672
- {
18673
- type: "checkbox",
18674
- checked: allSelected,
18675
- onChange: toggleAll,
18676
- className: "w-4 h-4 accent-primary",
18677
- "aria-label": "Select all"
18678
- }
18679
- ),
18680
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "font-semibold", children: [
18681
- selectedIds.size,
18682
- " ",
18683
- t("common.selected") || "selected"
18684
- ] })
18685
- ] }),
18686
- /* @__PURE__ */ jsx(
18864
+ DataGrid.displayName = "DataGrid";
18865
+ }
18866
+ });
18867
+ function fieldLabel3(key) {
18868
+ return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
18869
+ }
18870
+ function statusVariant3(value) {
18871
+ const v = value.toLowerCase();
18872
+ if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
18873
+ if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
18874
+ if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
18875
+ if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
18876
+ return "default";
18877
+ }
18878
+ function formatDate3(value) {
18879
+ if (!value) return "";
18880
+ const d = new Date(String(value));
18881
+ if (isNaN(d.getTime())) return String(value);
18882
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
18883
+ }
18884
+ function formatValue2(value, format) {
18885
+ if (value === void 0 || value === null) return "";
18886
+ switch (format) {
18887
+ case "date":
18888
+ return formatDate3(value);
18889
+ case "currency":
18890
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
18891
+ case "number":
18892
+ return typeof value === "number" ? value.toLocaleString() : String(value);
18893
+ case "percent":
18894
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
18895
+ case "boolean":
18896
+ return value ? "Yes" : "No";
18897
+ default:
18898
+ return String(value);
18899
+ }
18900
+ }
18901
+ function groupData(items, field) {
18902
+ const groups = /* @__PURE__ */ new Map();
18903
+ for (const item of items) {
18904
+ const key = String(getNestedValue(item, field) ?? "");
18905
+ const group = groups.get(key);
18906
+ if (group) group.push(item);
18907
+ else groups.set(key, [item]);
18908
+ }
18909
+ return Array.from(groups.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
18910
+ }
18911
+ function DataList({
18912
+ entity,
18913
+ fields: fieldsProp,
18914
+ columns: columnsProp,
18915
+ itemActions,
18916
+ gap = "none",
18917
+ variant = "default",
18918
+ groupBy,
18919
+ senderField,
18920
+ currentUser,
18921
+ className,
18922
+ isLoading = false,
18923
+ error = null,
18924
+ // Gesture props: reorderable, swipeLeftEvent, swipeRightEvent, longPressEvent
18925
+ // are consumed by the compiler to wrap items in SwipeableRow/SortableList.
18926
+ // DataList destructures them here to prevent DOM passthrough.
18927
+ reorderable: _reorderable,
18928
+ reorderEvent: _reorderEvent,
18929
+ swipeLeftEvent: _swipeLeftEvent,
18930
+ swipeLeftActions: _swipeLeftActions,
18931
+ swipeRightEvent: _swipeRightEvent,
18932
+ swipeRightActions: _swipeRightActions,
18933
+ longPressEvent: _longPressEvent,
18934
+ infiniteScroll,
18935
+ loadMoreEvent,
18936
+ hasMore,
18937
+ children,
18938
+ pageSize = 5
18939
+ }) {
18940
+ const eventBus = useEventBus();
18941
+ const { t } = useTranslate();
18942
+ const [visibleCount, setVisibleCount] = React115__default.useState(pageSize || Infinity);
18943
+ const fields = fieldsProp ?? columnsProp ?? [];
18944
+ const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
18945
+ const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
18946
+ const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
18947
+ const titleField = fields.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fields[0];
18948
+ const badgeFields = fields.filter((f3) => f3.variant === "badge" && f3 !== titleField);
18949
+ const progressFields = fields.filter((f3) => f3.variant === "progress");
18950
+ const bodyFields = fields.filter(
18951
+ (f3) => f3 !== titleField && !badgeFields.includes(f3) && !progressFields.includes(f3)
18952
+ );
18953
+ const handleActionClick = (action, itemData) => (e) => {
18954
+ e.stopPropagation();
18955
+ const payload = {
18956
+ id: itemData.id,
18957
+ row: itemData
18958
+ };
18959
+ eventBus.emit(`UI:${action.event}`, payload);
18960
+ };
18961
+ if (isLoading) {
18962
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
18963
+ }
18964
+ if (error) {
18965
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
18966
+ }
18967
+ if (data.length === 0) {
18968
+ return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18969
+ }
18970
+ const gapClass = {
18971
+ none: "",
18972
+ sm: "gap-1",
18973
+ md: "gap-2",
18974
+ lg: "gap-4"
18975
+ }[gap];
18976
+ const isCard = variant === "card";
18977
+ const isCompact = variant === "compact";
18978
+ const isMessage = variant === "message";
18979
+ if (isMessage) {
18980
+ const items2 = data.map((item) => item);
18981
+ const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
18982
+ const contentField = titleField?.name ?? fields[0]?.name ?? "";
18983
+ return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React115__default.Fragment, { children: [
18984
+ group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
18985
+ group.items.map((itemData, index) => {
18986
+ const id = itemData.id || `${gi}-${index}`;
18987
+ const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
18988
+ const isSent = Boolean(currentUser && sender === currentUser);
18989
+ const content = getNestedValue(itemData, contentField);
18990
+ const timestampField = fields.find((f3) => f3.format === "date");
18991
+ const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
18992
+ return /* @__PURE__ */ jsx(
18687
18993
  Box,
18688
18994
  {
18689
- className: cn("grid", gapStyles6[gap], colsClass, className),
18690
- style: gridTemplateColumns ? { gridTemplateColumns } : void 0,
18691
- children: data.map((item, index) => {
18692
- const itemData = item;
18693
- const id = itemData.id || String(index);
18694
- const isSelected = selectedIds.has(id);
18695
- if (hasRenderProp) {
18696
- return /* @__PURE__ */ jsx(
18697
- Box,
18698
- {
18699
- "data-entity-row": true,
18700
- "data-entity-id": id,
18701
- className: cn(
18702
- "bg-card rounded-lg",
18703
- "border border-border",
18704
- "shadow-sm hover:shadow-lg",
18705
- "hover:border-primary transition-all",
18706
- "p-4",
18707
- isSelected && "ring-2 ring-primary border-primary"
18708
- ),
18709
- children: children(itemData, index)
18710
- },
18711
- id
18712
- );
18995
+ className: cn(
18996
+ "flex px-4",
18997
+ isSent ? "justify-end" : "justify-start"
18998
+ ),
18999
+ children: /* @__PURE__ */ jsxs(
19000
+ Box,
19001
+ {
19002
+ className: cn(
19003
+ "max-w-[75%] px-4 py-2",
19004
+ isSent ? "bg-primary text-primary-foreground rounded-2xl rounded-br-sm" : "bg-muted text-foreground rounded-2xl rounded-bl-sm"
19005
+ ),
19006
+ children: [
19007
+ !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
19008
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
19009
+ timestamp != null ? /* @__PURE__ */ jsx(
19010
+ Typography,
19011
+ {
19012
+ variant: "caption",
19013
+ className: cn(
19014
+ "mt-1 text-[0.65rem]",
19015
+ isSent ? "opacity-70" : "text-muted-foreground"
19016
+ ),
19017
+ children: formatDate3(timestamp)
19018
+ }
19019
+ ) : null
19020
+ ]
18713
19021
  }
18714
- const titleValue = getNestedValue(itemData, titleField?.name ?? "");
18715
- return /* @__PURE__ */ jsxs(
18716
- Box,
19022
+ )
19023
+ },
19024
+ id
19025
+ );
19026
+ })
19027
+ ] }, gi)) });
19028
+ }
19029
+ const hasRenderProp = typeof children === "function";
19030
+ const items = data.map((item) => item);
19031
+ const groups = groupBy ? groupData(items, groupBy) : [{ label: "", items }];
19032
+ const renderItem = (itemData, index, isLast) => {
19033
+ if (hasRenderProp) {
19034
+ const id2 = itemData.id || String(index);
19035
+ return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
19036
+ /* @__PURE__ */ jsxs(
19037
+ Box,
19038
+ {
19039
+ className: cn(
19040
+ "group flex items-center gap-4 transition-all duration-200",
19041
+ isCompact ? "px-4 py-2" : "px-6 py-4",
19042
+ "hover:bg-muted/80",
19043
+ !isCard && !isCompact && "rounded-lg border border-transparent hover:border-border"
19044
+ ),
19045
+ children: [
19046
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
19047
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
19048
+ HStack,
18717
19049
  {
18718
- "data-entity-row": true,
18719
- "data-entity-id": id,
18720
- className: cn(
18721
- "bg-card rounded-lg",
18722
- "border border-border",
18723
- "shadow-sm hover:shadow-lg",
18724
- "hover:border-primary transition-all",
18725
- "flex flex-col",
18726
- isSelected && "ring-2 ring-primary border-primary"
18727
- ),
18728
- children: [
18729
- imageField && (() => {
18730
- const imgUrl = getNestedValue(itemData, imageField);
18731
- if (!imgUrl || typeof imgUrl !== "string") return null;
18732
- return /* @__PURE__ */ jsx(Box, { className: "w-full aspect-video overflow-hidden rounded-t-lg", children: /* @__PURE__ */ jsx(
18733
- "img",
18734
- {
18735
- src: imgUrl,
18736
- alt: titleValue !== void 0 ? String(titleValue) : "",
18737
- className: "w-full h-full object-cover",
18738
- loading: "lazy"
18739
- }
18740
- ) });
18741
- })(),
18742
- /* @__PURE__ */ jsx(Box, { className: "p-4 pb-0", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-start", children: [
18743
- selectable && /* @__PURE__ */ jsx(
18744
- "input",
18745
- {
18746
- type: "checkbox",
18747
- checked: isSelected,
18748
- onChange: () => toggleSelection(id),
18749
- onClick: (e) => e.stopPropagation(),
18750
- className: "w-4 h-4 mt-1 flex-shrink-0 accent-primary",
18751
- "aria-label": `Select ${titleValue !== void 0 ? String(titleValue) : "item"}`
18752
- }
19050
+ gap: "xs",
19051
+ className: "flex-shrink-0",
19052
+ children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
19053
+ Button,
19054
+ {
19055
+ variant: action.variant ?? "ghost",
19056
+ size: "sm",
19057
+ onClick: handleActionClick(action, itemData),
19058
+ "data-testid": `action-${action.event}`,
19059
+ className: cn(
19060
+ action.variant === "danger" && "text-error hover:bg-error/10"
18753
19061
  ),
18754
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
18755
- titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18756
- titleField?.icon && /* @__PURE__ */ jsx(Icon, { name: titleField.icon, size: "sm", className: "text-primary flex-shrink-0" }),
18757
- /* @__PURE__ */ jsx(
18758
- Typography,
18759
- {
18760
- variant: titleField?.variant === "h3" ? "h3" : "h4",
18761
- className: "font-semibold truncate",
18762
- children: String(titleValue)
18763
- }
18764
- )
18765
- ] }),
18766
- badgeFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: badgeFields.map((field) => {
18767
- const val = getNestedValue(itemData, field.name);
18768
- if (val === void 0 || val === null) return null;
18769
- return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18770
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
18771
- /* @__PURE__ */ jsx(Badge, { variant: statusVariant2(String(val)), children: String(val) })
18772
- ] }, field.name);
18773
- }) })
18774
- ] }),
18775
- dangerActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: dangerActions.map((action, idx) => /* @__PURE__ */ jsxs(
18776
- Button,
18777
- {
18778
- variant: "ghost",
18779
- size: "sm",
18780
- onClick: handleActionClick(action, itemData),
18781
- "data-testid": `action-${action.event}`,
18782
- className: "text-error hover:bg-error/10 px-2",
18783
- children: [
18784
- action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs" }),
18785
- action.label
18786
- ]
18787
- },
18788
- idx
18789
- )) })
18790
- ] }) }),
18791
- bodyFields.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 flex-1", children: /* @__PURE__ */ jsx(VStack, { gap: "xs", children: bodyFields.map((field) => {
18792
- const value = getNestedValue(itemData, field.name);
18793
- if (value === void 0 || value === null || value === "") return null;
18794
- if (field.format === "boolean") {
18795
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
18796
- /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18797
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
18798
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
18799
- ] }),
18800
- /* @__PURE__ */ jsx(Badge, { variant: value ? "success" : "neutral", children: value ? t("common.yes") || "Yes" : t("common.no") || "No" })
18801
- ] }, field.name);
18802
- }
18803
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-between items-center", children: [
18804
- /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
18805
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
18806
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel2(field.name) })
18807
- ] }),
18808
- /* @__PURE__ */ jsx(
18809
- Typography,
18810
- {
18811
- variant: field.variant === "caption" ? "caption" : "small",
18812
- className: "text-right truncate max-w-[60%]",
18813
- children: formatValue(value, field.format)
18814
- }
18815
- )
18816
- ] }, field.name);
18817
- }) }) }),
18818
- primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "justify-end", children: primaryActions.map((action, idx) => /* @__PURE__ */ jsxs(
18819
- Button,
18820
- {
18821
- variant: action.variant === "primary" ? "primary" : "ghost",
18822
- size: "sm",
18823
- onClick: handleActionClick(action, itemData),
18824
- "data-testid": `action-${action.event}`,
18825
- children: [
18826
- action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
18827
- action.label
18828
- ]
18829
- },
18830
- idx
18831
- )) }) })
18832
- ]
18833
- },
18834
- id
18835
- );
18836
- })
19062
+ children: [
19063
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
19064
+ action.label
19065
+ ]
19066
+ },
19067
+ idx
19068
+ ))
19069
+ }
19070
+ )
19071
+ ]
18837
19072
  }
18838
19073
  ),
19074
+ isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-border/40" })
19075
+ ] }, id2);
19076
+ }
19077
+ const id = itemData.id || String(index);
19078
+ const titleValue = getNestedValue(itemData, titleField?.name ?? "");
19079
+ return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
19080
+ /* @__PURE__ */ jsxs(
19081
+ Box,
19082
+ {
19083
+ className: cn(
19084
+ "group flex items-center gap-4 transition-all duration-200",
19085
+ isCompact ? "px-4 py-2" : "px-6 py-4",
19086
+ "hover:bg-muted/80",
19087
+ !isCard && !isCompact && "rounded-lg border border-transparent hover:border-border"
19088
+ ),
19089
+ children: [
19090
+ /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
19091
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
19092
+ titleField?.icon && /* @__PURE__ */ jsx(
19093
+ Icon,
19094
+ {
19095
+ name: titleField.icon,
19096
+ size: isCompact ? "xs" : "sm",
19097
+ className: "text-primary flex-shrink-0"
19098
+ }
19099
+ ),
19100
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
19101
+ Typography,
19102
+ {
19103
+ variant: titleField?.variant === "h3" ? "h3" : "h4",
19104
+ className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
19105
+ children: String(titleValue)
19106
+ }
19107
+ ),
19108
+ badgeFields.map((field) => {
19109
+ const val = getNestedValue(itemData, field.name);
19110
+ if (val === void 0 || val === null) return null;
19111
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
19112
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
19113
+ /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(val)), children: String(val) })
19114
+ ] }, field.name);
19115
+ })
19116
+ ] }),
19117
+ bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
19118
+ const value = getNestedValue(itemData, field.name);
19119
+ if (value === void 0 || value === null || value === "") return null;
19120
+ return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
19121
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
19122
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
19123
+ field.label ?? fieldLabel3(field.name),
19124
+ ":"
19125
+ ] }),
19126
+ /* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
19127
+ ] }, field.name);
19128
+ }) }),
19129
+ progressFields.map((field) => {
19130
+ const value = getNestedValue(itemData, field.name);
19131
+ if (typeof value !== "number") return null;
19132
+ return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
19133
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
19134
+ field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
19135
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel3(field.name) })
19136
+ ] }),
19137
+ /* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
19138
+ ] }, field.name);
19139
+ })
19140
+ ] }),
19141
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
19142
+ Button,
19143
+ {
19144
+ variant: action.variant ?? "ghost",
19145
+ size: "sm",
19146
+ onClick: handleActionClick(action, itemData),
19147
+ "data-testid": `action-${action.event}`,
19148
+ className: cn(
19149
+ action.variant === "danger" && "text-error hover:bg-error/10"
19150
+ ),
19151
+ children: [
19152
+ action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
19153
+ action.label
19154
+ ]
19155
+ },
19156
+ idx
19157
+ )) })
19158
+ ]
19159
+ }
19160
+ ),
19161
+ isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-border/40" })
19162
+ ] }, id);
19163
+ };
19164
+ return /* @__PURE__ */ jsxs(
19165
+ Box,
19166
+ {
19167
+ className: cn(
19168
+ isCard && "bg-card rounded-xl border border-border shadow-lg overflow-hidden",
19169
+ !isCard && gapClass,
19170
+ className
19171
+ ),
19172
+ children: [
19173
+ groups.map((group, gi) => /* @__PURE__ */ jsxs(React115__default.Fragment, { children: [
19174
+ group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
19175
+ group.items.map(
19176
+ (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
19177
+ )
19178
+ ] }, gi)),
18839
19179
  hasMoreLocal && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(
18840
19180
  Button,
18841
19181
  {
@@ -18859,56 +19199,10 @@ var init_DataGrid = __esm({
18859
19199
  hasMore
18860
19200
  }
18861
19201
  )
18862
- ] });
18863
- };
18864
- DataGrid.displayName = "DataGrid";
18865
- }
18866
- });
18867
- function fieldLabel3(key) {
18868
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
18869
- }
18870
- function statusVariant3(value) {
18871
- const v = value.toLowerCase();
18872
- if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
18873
- if (["pending", "in_progress", "in-progress", "review", "draft", "processing", "warning"].includes(v)) return "warning";
18874
- if (["inactive", "deleted", "rejected", "failed", "error", "blocked", "closed", "offline"].includes(v)) return "error";
18875
- if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
18876
- return "default";
18877
- }
18878
- function formatDate3(value) {
18879
- if (!value) return "";
18880
- const d = new Date(String(value));
18881
- if (isNaN(d.getTime())) return String(value);
18882
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
18883
- }
18884
- function formatValue2(value, format) {
18885
- if (value === void 0 || value === null) return "";
18886
- switch (format) {
18887
- case "date":
18888
- return formatDate3(value);
18889
- case "currency":
18890
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
18891
- case "number":
18892
- return typeof value === "number" ? value.toLocaleString() : String(value);
18893
- case "percent":
18894
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
18895
- case "boolean":
18896
- return value ? "Yes" : "No";
18897
- default:
18898
- return String(value);
18899
- }
18900
- }
18901
- function groupData(items, field) {
18902
- const groups = /* @__PURE__ */ new Map();
18903
- for (const item of items) {
18904
- const key = String(getNestedValue(item, field) ?? "");
18905
- const group = groups.get(key);
18906
- if (group) group.push(item);
18907
- else groups.set(key, [item]);
18908
- }
18909
- return Array.from(groups.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
19202
+ ]
19203
+ }
19204
+ );
18910
19205
  }
18911
- var DataList;
18912
19206
  var init_DataList = __esm({
18913
19207
  "components/molecules/DataList.tsx"() {
18914
19208
  "use client";
@@ -18925,301 +19219,6 @@ var init_DataList = __esm({
18925
19219
  init_ProgressBar();
18926
19220
  init_Divider();
18927
19221
  init_InfiniteScrollSentinel();
18928
- DataList = ({
18929
- entity,
18930
- fields: fieldsProp,
18931
- columns: columnsProp,
18932
- itemActions,
18933
- gap = "none",
18934
- variant = "default",
18935
- groupBy,
18936
- senderField,
18937
- currentUser,
18938
- className,
18939
- isLoading = false,
18940
- error = null,
18941
- // Gesture props: reorderable, swipeLeftEvent, swipeRightEvent, longPressEvent
18942
- // are consumed by the compiler to wrap items in SwipeableRow/SortableList.
18943
- // DataList destructures them here to prevent DOM passthrough.
18944
- reorderable: _reorderable,
18945
- reorderEvent: _reorderEvent,
18946
- swipeLeftEvent: _swipeLeftEvent,
18947
- swipeLeftActions: _swipeLeftActions,
18948
- swipeRightEvent: _swipeRightEvent,
18949
- swipeRightActions: _swipeRightActions,
18950
- longPressEvent: _longPressEvent,
18951
- infiniteScroll,
18952
- loadMoreEvent,
18953
- hasMore,
18954
- children,
18955
- pageSize = 5
18956
- }) => {
18957
- const eventBus = useEventBus();
18958
- const { t } = useTranslate();
18959
- const [visibleCount, setVisibleCount] = React115__default.useState(pageSize || Infinity);
18960
- const fields = fieldsProp ?? columnsProp ?? [];
18961
- const allData = Array.isArray(entity) ? entity : entity ? [entity] : [];
18962
- const data = pageSize > 0 ? allData.slice(0, visibleCount) : allData;
18963
- const hasMoreLocal = pageSize > 0 && visibleCount < allData.length;
18964
- const titleField = fields.find((f3) => f3.variant === "h3" || f3.variant === "h4") ?? fields[0];
18965
- const badgeFields = fields.filter((f3) => f3.variant === "badge" && f3 !== titleField);
18966
- const progressFields = fields.filter((f3) => f3.variant === "progress");
18967
- const bodyFields = fields.filter(
18968
- (f3) => f3 !== titleField && !badgeFields.includes(f3) && !progressFields.includes(f3)
18969
- );
18970
- const handleActionClick = (action, itemData) => (e) => {
18971
- e.stopPropagation();
18972
- const payload = {
18973
- id: itemData.id,
18974
- row: itemData
18975
- };
18976
- eventBus.emit(`UI:${action.event}`, payload);
18977
- };
18978
- if (isLoading) {
18979
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") || "Loading..." }) });
18980
- }
18981
- if (error) {
18982
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
18983
- }
18984
- if (data.length === 0) {
18985
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18986
- }
18987
- const gapClass = {
18988
- none: "",
18989
- sm: "gap-1",
18990
- md: "gap-2",
18991
- lg: "gap-4"
18992
- }[gap];
18993
- const isCard = variant === "card";
18994
- const isCompact = variant === "compact";
18995
- const isMessage = variant === "message";
18996
- if (isMessage) {
18997
- const items2 = data.map((item) => item);
18998
- const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
18999
- const contentField = titleField?.name ?? fields[0]?.name ?? "";
19000
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React115__default.Fragment, { children: [
19001
- group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
19002
- group.items.map((itemData, index) => {
19003
- const id = itemData.id || `${gi}-${index}`;
19004
- const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
19005
- const isSent = Boolean(currentUser && sender === currentUser);
19006
- const content = getNestedValue(itemData, contentField);
19007
- const timestampField = fields.find((f3) => f3.format === "date");
19008
- const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
19009
- return /* @__PURE__ */ jsx(
19010
- Box,
19011
- {
19012
- className: cn(
19013
- "flex px-4",
19014
- isSent ? "justify-end" : "justify-start"
19015
- ),
19016
- children: /* @__PURE__ */ jsxs(
19017
- Box,
19018
- {
19019
- className: cn(
19020
- "max-w-[75%] px-4 py-2",
19021
- isSent ? "bg-primary text-primary-foreground rounded-2xl rounded-br-sm" : "bg-muted text-foreground rounded-2xl rounded-bl-sm"
19022
- ),
19023
- children: [
19024
- !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
19025
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: content !== void 0 && content !== null ? String(content) : "" }),
19026
- timestamp != null ? /* @__PURE__ */ jsx(
19027
- Typography,
19028
- {
19029
- variant: "caption",
19030
- className: cn(
19031
- "mt-1 text-[0.65rem]",
19032
- isSent ? "opacity-70" : "text-muted-foreground"
19033
- ),
19034
- children: formatDate3(timestamp)
19035
- }
19036
- ) : null
19037
- ]
19038
- }
19039
- )
19040
- },
19041
- id
19042
- );
19043
- })
19044
- ] }, gi)) });
19045
- }
19046
- const hasRenderProp = typeof children === "function";
19047
- const items = data.map((item) => item);
19048
- const groups = groupBy ? groupData(items, groupBy) : [{ label: "", items }];
19049
- const renderItem = (itemData, index, isLast) => {
19050
- if (hasRenderProp) {
19051
- const id2 = itemData.id || String(index);
19052
- return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id2, children: [
19053
- /* @__PURE__ */ jsxs(
19054
- Box,
19055
- {
19056
- className: cn(
19057
- "group flex items-center gap-4 transition-all duration-200",
19058
- isCompact ? "px-4 py-2" : "px-6 py-4",
19059
- "hover:bg-muted/80",
19060
- !isCard && !isCompact && "rounded-lg border border-transparent hover:border-border"
19061
- ),
19062
- children: [
19063
- /* @__PURE__ */ jsx(Box, { className: "flex-1 min-w-0", children: children(itemData, index) }),
19064
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(
19065
- HStack,
19066
- {
19067
- gap: "xs",
19068
- className: "flex-shrink-0",
19069
- children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
19070
- Button,
19071
- {
19072
- variant: action.variant ?? "ghost",
19073
- size: "sm",
19074
- onClick: handleActionClick(action, itemData),
19075
- "data-testid": `action-${action.event}`,
19076
- className: cn(
19077
- action.variant === "danger" && "text-error hover:bg-error/10"
19078
- ),
19079
- children: [
19080
- action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
19081
- action.label
19082
- ]
19083
- },
19084
- idx
19085
- ))
19086
- }
19087
- )
19088
- ]
19089
- }
19090
- ),
19091
- isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-border/40" })
19092
- ] }, id2);
19093
- }
19094
- const id = itemData.id || String(index);
19095
- const titleValue = getNestedValue(itemData, titleField?.name ?? "");
19096
- return /* @__PURE__ */ jsxs(Box, { "data-entity-row": true, "data-entity-id": id, children: [
19097
- /* @__PURE__ */ jsxs(
19098
- Box,
19099
- {
19100
- className: cn(
19101
- "group flex items-center gap-4 transition-all duration-200",
19102
- isCompact ? "px-4 py-2" : "px-6 py-4",
19103
- "hover:bg-muted/80",
19104
- !isCard && !isCompact && "rounded-lg border border-transparent hover:border-border"
19105
- ),
19106
- children: [
19107
- /* @__PURE__ */ jsxs(Box, { className: "flex-1 min-w-0", children: [
19108
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
19109
- titleField?.icon && /* @__PURE__ */ jsx(
19110
- Icon,
19111
- {
19112
- name: titleField.icon,
19113
- size: isCompact ? "xs" : "sm",
19114
- className: "text-primary flex-shrink-0"
19115
- }
19116
- ),
19117
- titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsx(
19118
- Typography,
19119
- {
19120
- variant: titleField?.variant === "h3" ? "h3" : "h4",
19121
- className: cn("font-semibold truncate flex-1", isCompact && "text-sm"),
19122
- children: String(titleValue)
19123
- }
19124
- ),
19125
- badgeFields.map((field) => {
19126
- const val = getNestedValue(itemData, field.name);
19127
- if (val === void 0 || val === null) return null;
19128
- return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center flex-shrink-0", children: [
19129
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs" }),
19130
- /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(val)), children: String(val) })
19131
- ] }, field.name);
19132
- })
19133
- ] }),
19134
- bodyFields.length > 0 && !isCompact && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "mt-1.5 flex-wrap", children: bodyFields.map((field) => {
19135
- const value = getNestedValue(itemData, field.name);
19136
- if (value === void 0 || value === null || value === "") return null;
19137
- return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
19138
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
19139
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", color: "secondary", children: [
19140
- field.label ?? fieldLabel3(field.name),
19141
- ":"
19142
- ] }),
19143
- /* @__PURE__ */ jsx(Typography, { variant: "small", children: formatValue2(value, field.format) })
19144
- ] }, field.name);
19145
- }) }),
19146
- progressFields.map((field) => {
19147
- const value = getNestedValue(itemData, field.name);
19148
- if (typeof value !== "number") return null;
19149
- return /* @__PURE__ */ jsxs(Box, { className: "mt-2 max-w-xs", children: [
19150
- /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center mb-1", children: [
19151
- field.icon && /* @__PURE__ */ jsx(Icon, { name: field.icon, size: "xs", className: "text-muted-foreground" }),
19152
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: field.label ?? fieldLabel3(field.name) })
19153
- ] }),
19154
- /* @__PURE__ */ jsx(ProgressBar, { value, max: 100 })
19155
- ] }, field.name);
19156
- })
19157
- ] }),
19158
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-shrink-0", children: itemActions.map((action, idx) => /* @__PURE__ */ jsxs(
19159
- Button,
19160
- {
19161
- variant: action.variant ?? "ghost",
19162
- size: "sm",
19163
- onClick: handleActionClick(action, itemData),
19164
- "data-testid": `action-${action.event}`,
19165
- className: cn(
19166
- action.variant === "danger" && "text-error hover:bg-error/10"
19167
- ),
19168
- children: [
19169
- action.icon && /* @__PURE__ */ jsx(Icon, { name: action.icon, size: "xs", className: "mr-1" }),
19170
- action.label
19171
- ]
19172
- },
19173
- idx
19174
- )) })
19175
- ]
19176
- }
19177
- ),
19178
- isCard && !isLast && /* @__PURE__ */ jsx(Box, { className: "mx-6 border-b border-border/40" })
19179
- ] }, id);
19180
- };
19181
- return /* @__PURE__ */ jsxs(
19182
- Box,
19183
- {
19184
- className: cn(
19185
- isCard && "bg-card rounded-xl border border-border shadow-lg overflow-hidden",
19186
- !isCard && gapClass,
19187
- className
19188
- ),
19189
- children: [
19190
- groups.map((group, gi) => /* @__PURE__ */ jsxs(React115__default.Fragment, { children: [
19191
- group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-4" : "mt-0" }),
19192
- group.items.map(
19193
- (itemData, index) => renderItem(itemData, index, gi === groups.length - 1 && index === group.items.length - 1)
19194
- )
19195
- ] }, gi)),
19196
- hasMoreLocal && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(
19197
- Button,
19198
- {
19199
- variant: "ghost",
19200
- size: "sm",
19201
- onClick: () => setVisibleCount((prev) => prev + (pageSize || 5)),
19202
- children: [
19203
- /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
19204
- t("common.showMore"),
19205
- " (",
19206
- allData.length - visibleCount,
19207
- " remaining)"
19208
- ]
19209
- }
19210
- ) }),
19211
- infiniteScroll && loadMoreEvent && /* @__PURE__ */ jsx(
19212
- InfiniteScrollSentinel,
19213
- {
19214
- loadMoreEvent,
19215
- isLoading,
19216
- hasMore
19217
- }
19218
- )
19219
- ]
19220
- }
19221
- );
19222
- };
19223
19222
  DataList.displayName = "DataList";
19224
19223
  }
19225
19224
  });
@@ -20420,7 +20419,10 @@ var init_WizardProgress = __esm({
20420
20419
  stepClickEvent
20421
20420
  }) => {
20422
20421
  const eventBus = useEventBus();
20423
- const totalSteps = steps.length;
20422
+ const normalizedSteps = steps.map(
20423
+ (s, i) => typeof s === "string" ? { id: `step-${i}`, title: s } : s
20424
+ );
20425
+ const totalSteps = normalizedSteps.length;
20424
20426
  const handleStepClick = (index) => {
20425
20427
  const isCompleted = index < currentStep;
20426
20428
  if (isCompleted && allowNavigation) {
@@ -20437,7 +20439,7 @@ var init_WizardProgress = __esm({
20437
20439
  compact ? "px-4 py-2" : "px-6 py-4",
20438
20440
  className
20439
20441
  ),
20440
- children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: steps.map((step, index) => {
20442
+ children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: normalizedSteps.map((step, index) => {
20441
20443
  const isActive = index === currentStep;
20442
20444
  const isCompleted = index < currentStep;
20443
20445
  return /* @__PURE__ */ jsxs(React115__default.Fragment, { children: [
@@ -38633,161 +38635,6 @@ function OrbitalProvider({
38633
38635
  );
38634
38636
  }
38635
38637
  OrbitalProvider.displayName = "OrbitalProvider";
38636
- var FetchedDataContext = createContext(null);
38637
- function FetchedDataProvider({
38638
- initialData,
38639
- children
38640
- }) {
38641
- const [state, setState] = useState(() => ({
38642
- data: initialData || {},
38643
- fetchedAt: {},
38644
- loading: false,
38645
- error: null
38646
- }));
38647
- const getData = useCallback(
38648
- (entityName) => {
38649
- return state.data[entityName] || [];
38650
- },
38651
- [state.data]
38652
- );
38653
- const getById = useCallback(
38654
- (entityName, id) => {
38655
- const records = state.data[entityName];
38656
- return records?.find((r) => r.id === id);
38657
- },
38658
- [state.data]
38659
- );
38660
- const hasData = useCallback(
38661
- (entityName) => {
38662
- return entityName in state.data && state.data[entityName].length > 0;
38663
- },
38664
- [state.data]
38665
- );
38666
- const getFetchedAt = useCallback(
38667
- (entityName) => {
38668
- return state.fetchedAt[entityName];
38669
- },
38670
- [state.fetchedAt]
38671
- );
38672
- const setData = useCallback((data) => {
38673
- const now = Date.now();
38674
- setState((prev) => ({
38675
- ...prev,
38676
- data: {
38677
- ...prev.data,
38678
- ...data
38679
- },
38680
- fetchedAt: {
38681
- ...prev.fetchedAt,
38682
- ...Object.keys(data).reduce(
38683
- (acc, key) => ({ ...acc, [key]: now }),
38684
- {}
38685
- )
38686
- },
38687
- loading: false,
38688
- error: null
38689
- }));
38690
- }, []);
38691
- const clearData = useCallback(() => {
38692
- setState((prev) => ({
38693
- ...prev,
38694
- data: {},
38695
- fetchedAt: {}
38696
- }));
38697
- }, []);
38698
- const clearEntity = useCallback((entityName) => {
38699
- setState((prev) => {
38700
- const newData = { ...prev.data };
38701
- const newFetchedAt = { ...prev.fetchedAt };
38702
- delete newData[entityName];
38703
- delete newFetchedAt[entityName];
38704
- return {
38705
- ...prev,
38706
- data: newData,
38707
- fetchedAt: newFetchedAt
38708
- };
38709
- });
38710
- }, []);
38711
- const setLoading = useCallback((loading) => {
38712
- setState((prev) => ({ ...prev, loading }));
38713
- }, []);
38714
- const setError = useCallback((error) => {
38715
- setState((prev) => ({ ...prev, error, loading: false }));
38716
- }, []);
38717
- const contextValue = useMemo(
38718
- () => ({
38719
- getData,
38720
- getById,
38721
- hasData,
38722
- getFetchedAt,
38723
- setData,
38724
- clearData,
38725
- clearEntity,
38726
- loading: state.loading,
38727
- setLoading,
38728
- error: state.error,
38729
- setError
38730
- }),
38731
- [
38732
- getData,
38733
- getById,
38734
- hasData,
38735
- getFetchedAt,
38736
- setData,
38737
- clearData,
38738
- clearEntity,
38739
- state.loading,
38740
- setLoading,
38741
- state.error,
38742
- setError
38743
- ]
38744
- );
38745
- return /* @__PURE__ */ jsx(FetchedDataContext.Provider, { value: contextValue, children });
38746
- }
38747
- function useFetchedDataContext() {
38748
- return useContext(FetchedDataContext);
38749
- }
38750
- function useFetchedData() {
38751
- const context = useContext(FetchedDataContext);
38752
- if (!context) {
38753
- return {
38754
- getData: () => [],
38755
- getById: () => void 0,
38756
- hasData: () => false,
38757
- getFetchedAt: () => void 0,
38758
- setData: () => {
38759
- },
38760
- clearData: () => {
38761
- },
38762
- clearEntity: () => {
38763
- },
38764
- loading: false,
38765
- setLoading: () => {
38766
- },
38767
- error: null,
38768
- setError: () => {
38769
- }
38770
- };
38771
- }
38772
- return context;
38773
- }
38774
- function useFetchedEntity(entityName) {
38775
- const context = useFetchedData();
38776
- return {
38777
- /** All fetched records for this entity */
38778
- records: context.getData(entityName),
38779
- /** Get a record by ID */
38780
- getById: (id) => context.getById(entityName, id),
38781
- /** Whether data has been fetched for this entity */
38782
- hasData: context.hasData(entityName),
38783
- /** When data was last fetched */
38784
- fetchedAt: context.getFetchedAt(entityName),
38785
- /** Whether data is loading */
38786
- loading: context.loading,
38787
- /** Current error */
38788
- error: context.error
38789
- };
38790
- }
38791
38638
 
38792
38639
  // providers/OfflineModeProvider.tsx
38793
38640
  init_offline_executor();
@@ -38821,4 +38668,4 @@ function useOptionalOfflineMode() {
38821
38668
  return useContext(OfflineModeContext);
38822
38669
  }
38823
38670
 
38824
- export { EventBusContext2 as EventBusContext, EventBusProvider, FetchedDataContext, FetchedDataProvider, OfflineModeProvider, OrbitalProvider, SelectionContext, SelectionProvider, VerificationProvider, useFetchedData, useFetchedDataContext, useFetchedEntity, useOfflineMode, useOptionalOfflineMode, useSelection, useSelectionOptional };
38671
+ export { EventBusContext2 as EventBusContext, EventBusProvider, OfflineModeProvider, OrbitalProvider, SelectionContext, SelectionProvider, VerificationProvider, useOfflineMode, useOptionalOfflineMode, useSelection, useSelectionOptional };