@almadar/ui 5.133.0 → 5.134.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.
@@ -3980,6 +3980,61 @@ var init_TextHighlight = __esm({
3980
3980
  }
3981
3981
  });
3982
3982
 
3983
+ // lib/format.ts
3984
+ function humanizeFieldName(name) {
3985
+ return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\b([A-Z])([A-Z]+)\b/g, (_, first, rest) => first + rest.toLowerCase()).trim();
3986
+ }
3987
+ function humanizeEnumValue(value) {
3988
+ return /^[a-z0-9]+(?:[_-][a-z0-9]+)+$/.test(value) ? humanizeFieldName(value) : value;
3989
+ }
3990
+ function formatDate(value) {
3991
+ if (!value) return "";
3992
+ const d = new Date(String(value));
3993
+ if (isNaN(d.getTime())) return String(value);
3994
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
3995
+ }
3996
+ function formatTime(value) {
3997
+ if (!value) return "";
3998
+ const d = new Date(String(value));
3999
+ if (isNaN(d.getTime())) return String(value);
4000
+ return d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
4001
+ }
4002
+ function formatDateTime(value) {
4003
+ if (!value) return "";
4004
+ const d = new Date(String(value));
4005
+ if (isNaN(d.getTime())) return String(value);
4006
+ return `${formatDate(value)} ${formatTime(value)}`;
4007
+ }
4008
+ function asYesNo(value) {
4009
+ return value === false || value === 0 || String(value) === "false" ? "No" : "Yes";
4010
+ }
4011
+ function formatValue(value, format) {
4012
+ if (value === void 0 || value === null) return "";
4013
+ if (typeof value === "boolean") return asYesNo(value);
4014
+ switch (format) {
4015
+ case "date":
4016
+ return formatDate(value);
4017
+ case "time":
4018
+ return formatTime(value);
4019
+ case "datetime":
4020
+ return formatDateTime(value);
4021
+ case "currency":
4022
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
4023
+ case "number":
4024
+ return typeof value === "number" ? value.toLocaleString() : String(value);
4025
+ case "percent":
4026
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
4027
+ case "boolean":
4028
+ return asYesNo(value);
4029
+ default:
4030
+ return String(value);
4031
+ }
4032
+ }
4033
+ var init_format = __esm({
4034
+ "lib/format.ts"() {
4035
+ }
4036
+ });
4037
+
3983
4038
  // components/core/atoms/Typography.tsx
3984
4039
  var Typography_exports = {};
3985
4040
  __export(Typography_exports, {
@@ -3989,6 +4044,7 @@ var variantStyles6, colorStyles, weightStyles, defaultElements, typographySizeSt
3989
4044
  var init_Typography = __esm({
3990
4045
  "components/core/atoms/Typography.tsx"() {
3991
4046
  init_cn();
4047
+ init_format();
3992
4048
  variantStyles6 = {
3993
4049
  h1: "text-4xl font-bold tracking-tight text-foreground",
3994
4050
  h2: "text-3xl font-bold tracking-tight text-foreground",
@@ -4076,11 +4132,16 @@ var init_Typography = __esm({
4076
4132
  id,
4077
4133
  className,
4078
4134
  style,
4135
+ format,
4079
4136
  content,
4080
4137
  children
4081
4138
  }) => {
4082
4139
  const variant = variantProp ?? (level ? `h${level}` : "body1");
4083
4140
  const Component = as || defaultElements[variant];
4141
+ let body = children ?? content;
4142
+ if (format !== void 0 && format !== "none" && (typeof body === "string" || typeof body === "number" || body instanceof Date)) {
4143
+ body = formatValue(body, format);
4144
+ }
4084
4145
  return React74__namespace.default.createElement(
4085
4146
  Component,
4086
4147
  {
@@ -4097,7 +4158,7 @@ var init_Typography = __esm({
4097
4158
  ),
4098
4159
  style
4099
4160
  },
4100
- children ?? content
4161
+ body
4101
4162
  );
4102
4163
  };
4103
4164
  exports.Typography.displayName = "Typography";
@@ -16672,9 +16733,6 @@ function normalizeFields(fields) {
16672
16733
  if (!fields) return [];
16673
16734
  return fields.map((f3) => typeof f3 === "string" ? f3 : f3.key ?? f3.name ?? "");
16674
16735
  }
16675
- function fieldLabel(key) {
16676
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
16677
- }
16678
16736
  function asBooleanValue(value) {
16679
16737
  if (typeof value === "boolean") return value;
16680
16738
  if (value === "true") return true;
@@ -16685,12 +16743,6 @@ function isDateField(key) {
16685
16743
  const lower = key.toLowerCase();
16686
16744
  return lower.includes("date") || lower.includes("time") || lower.endsWith("at") || lower.endsWith("_at");
16687
16745
  }
16688
- function formatDate(value) {
16689
- if (!value) return "";
16690
- const d = new Date(String(value));
16691
- if (isNaN(d.getTime())) return String(value);
16692
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
16693
- }
16694
16746
  function statusVariant(value) {
16695
16747
  const v = value.toLowerCase();
16696
16748
  if (["active", "completed", "done", "approved", "published", "resolved", "open"].includes(v)) return "success";
@@ -16699,11 +16751,12 @@ function statusVariant(value) {
16699
16751
  if (["new", "created", "scheduled", "queued"].includes(v)) return "info";
16700
16752
  return "default";
16701
16753
  }
16702
- var STATUS_FIELDS, gapStyles3, alignStyles2; exports.CardGrid = void 0;
16754
+ var fieldLabel, STATUS_FIELDS, gapStyles3, alignStyles2; exports.CardGrid = void 0;
16703
16755
  var init_CardGrid = __esm({
16704
16756
  "components/core/organisms/CardGrid.tsx"() {
16705
16757
  "use client";
16706
16758
  init_cn();
16759
+ init_format();
16707
16760
  init_getNestedValue();
16708
16761
  init_useEventBus();
16709
16762
  init_atoms();
@@ -16712,6 +16765,7 @@ var init_CardGrid = __esm({
16712
16765
  init_Typography();
16713
16766
  init_Stack();
16714
16767
  init_Pagination();
16768
+ fieldLabel = humanizeFieldName;
16715
16769
  STATUS_FIELDS = /* @__PURE__ */ new Set(["status", "state", "priority", "type", "category", "role", "level", "tier"]);
16716
16770
  gapStyles3 = {
16717
16771
  none: "gap-0",
@@ -17219,7 +17273,7 @@ var init_CaseStudyOrganism = __esm({
17219
17273
  exports.CaseStudyOrganism.displayName = "CaseStudyOrganism";
17220
17274
  }
17221
17275
  });
17222
- var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, LOOK_FROM_CHART_TYPE; exports.Chart = void 0;
17276
+ var CHART_COLORS, seriesColor, barColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, LOOK_FROM_CHART_TYPE; exports.Chart = void 0;
17223
17277
  var init_Chart = __esm({
17224
17278
  "components/core/molecules/Chart.tsx"() {
17225
17279
  "use client";
@@ -17239,6 +17293,7 @@ var init_Chart = __esm({
17239
17293
  "var(--color-accent)"
17240
17294
  ];
17241
17295
  seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
17296
+ barColor = (series, sIdx, catIdx, seriesCount) => series.color ?? CHART_COLORS[(seriesCount === 1 ? catIdx : sIdx) % CHART_COLORS.length];
17242
17297
  monthFormatter = new Intl.DateTimeFormat(void 0, {
17243
17298
  month: "short",
17244
17299
  year: "2-digit"
@@ -17311,7 +17366,7 @@ var init_Chart = __esm({
17311
17366
  children: series.map((s, sIdx) => {
17312
17367
  const value = valueAt(s, label);
17313
17368
  const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
17314
- const color = seriesColor(s, sIdx);
17369
+ const color = barColor(s, sIdx, catIdx, series.length);
17315
17370
  return /* @__PURE__ */ jsxRuntime.jsx(
17316
17371
  exports.Box,
17317
17372
  {
@@ -17366,7 +17421,7 @@ var init_Chart = __esm({
17366
17421
  /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: histogram ? "none" : "xs", align: "end", justify: histogram ? void 0 : "center", className: "w-full flex-1 min-h-0", children: series.map((s, sIdx) => {
17367
17422
  const value = valueAt(s, label);
17368
17423
  const barHeight = value / maxValue * 100;
17369
- const color = seriesColor(s, sIdx);
17424
+ const color = barColor(s, sIdx, catIdx, series.length);
17370
17425
  return /* @__PURE__ */ jsxRuntime.jsx(
17371
17426
  exports.Box,
17372
17427
  {
@@ -17417,7 +17472,7 @@ var init_Chart = __esm({
17417
17472
  /* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "none", className: "w-full flex-1 min-h-0", justify: "end", children: series.map((s, sIdx) => {
17418
17473
  const value = valueAt(s, label);
17419
17474
  const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
17420
- const color = seriesColor(s, sIdx);
17475
+ const color = barColor(s, sIdx, catIdx, series.length);
17421
17476
  return /* @__PURE__ */ jsxRuntime.jsx(
17422
17477
  exports.Box,
17423
17478
  {
@@ -20652,9 +20707,6 @@ var init_useDataDnd = __esm({
20652
20707
  function renderIconInput(icon, props) {
20653
20708
  return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, ...props });
20654
20709
  }
20655
- function fieldLabel2(key) {
20656
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
20657
- }
20658
20710
  function statusVariant2(value) {
20659
20711
  const v = value.toLowerCase();
20660
20712
  if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
@@ -20673,29 +20725,6 @@ function resolveBadgeVariant(field, value) {
20673
20725
  }
20674
20726
  return statusVariant2(value);
20675
20727
  }
20676
- function formatDate2(value) {
20677
- if (!value) return "";
20678
- const d = new Date(String(value));
20679
- if (isNaN(d.getTime())) return String(value);
20680
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
20681
- }
20682
- function formatValue(value, format) {
20683
- if (value === void 0 || value === null) return "";
20684
- switch (format) {
20685
- case "date":
20686
- return formatDate2(value);
20687
- case "currency":
20688
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
20689
- case "number":
20690
- return typeof value === "number" ? value.toLocaleString() : String(value);
20691
- case "percent":
20692
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
20693
- case "boolean":
20694
- return value ? "Yes" : "No";
20695
- default:
20696
- return String(value);
20697
- }
20698
- }
20699
20728
  function DataGrid({
20700
20729
  entity,
20701
20730
  fields,
@@ -20982,7 +21011,7 @@ function DataGrid({
20982
21011
  if (val === void 0 || val === null || val === "") return null;
20983
21012
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", className: "items-center", children: [
20984
21013
  field.icon && renderIconInput(field.icon, { size: "xs" }),
20985
- /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: resolveBadgeVariant(field, String(val)), children: formatValue(val, field.format) })
21014
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: resolveBadgeVariant(field, String(val)), children: humanizeEnumValue(formatValue(val, field.format)) })
20986
21015
  ] }, field.name);
20987
21016
  }) })
20988
21017
  ] }),
@@ -21092,11 +21121,12 @@ function DataGrid({
21092
21121
  ] })
21093
21122
  );
21094
21123
  }
21095
- var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles5;
21124
+ var dataGridLog, fieldLabel2, BADGE_VARIANTS, gapStyles5, lookStyles5;
21096
21125
  var init_DataGrid = __esm({
21097
21126
  "components/core/molecules/DataGrid.tsx"() {
21098
21127
  "use client";
21099
21128
  init_cn();
21129
+ init_format();
21100
21130
  init_getNestedValue();
21101
21131
  init_useEventBus();
21102
21132
  init_Box();
@@ -21109,6 +21139,7 @@ var init_DataGrid = __esm({
21109
21139
  init_Menu();
21110
21140
  init_useDataDnd();
21111
21141
  dataGridLog = logger.createLogger("almadar:ui:data-grid");
21142
+ fieldLabel2 = humanizeFieldName;
21112
21143
  BADGE_VARIANTS = /* @__PURE__ */ new Set([
21113
21144
  "default",
21114
21145
  "primary",
@@ -21140,9 +21171,6 @@ var init_DataGrid = __esm({
21140
21171
  function renderIconInput2(icon, props) {
21141
21172
  return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, ...props });
21142
21173
  }
21143
- function fieldLabel3(key) {
21144
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
21145
- }
21146
21174
  function statusVariant3(value) {
21147
21175
  const v = value.toLowerCase();
21148
21176
  if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
@@ -21151,28 +21179,12 @@ function statusVariant3(value) {
21151
21179
  if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
21152
21180
  return "default";
21153
21181
  }
21154
- function formatDate3(value) {
21155
- if (!value) return "";
21156
- const d = new Date(String(value));
21157
- if (isNaN(d.getTime())) return String(value);
21158
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
21159
- }
21160
21182
  function formatValue2(value, format, boolLabels) {
21161
- if (value === void 0 || value === null) return "";
21162
- switch (format) {
21163
- case "date":
21164
- return formatDate3(value);
21165
- case "currency":
21166
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
21167
- case "number":
21168
- return typeof value === "number" ? value.toLocaleString() : String(value);
21169
- case "percent":
21170
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
21171
- case "boolean":
21172
- return value ? boolLabels?.yes ?? "Yes" : boolLabels?.no ?? "No";
21173
- default:
21174
- return String(value);
21183
+ if (value !== void 0 && value !== null && (format === "boolean" || typeof value === "boolean")) {
21184
+ const isNo = value === false || value === 0 || String(value) === "false";
21185
+ return isNo ? boolLabels?.no ?? "No" : boolLabels?.yes ?? "Yes";
21175
21186
  }
21187
+ return formatValue(value, format);
21176
21188
  }
21177
21189
  function groupData(items, field) {
21178
21190
  const groups = /* @__PURE__ */ new Map();
@@ -21195,7 +21207,9 @@ function DataList({
21195
21207
  variant = "default",
21196
21208
  groupBy,
21197
21209
  senderField,
21210
+ senderLabelField,
21198
21211
  currentUser,
21212
+ emptyMessage,
21199
21213
  className,
21200
21214
  isLoading = false,
21201
21215
  error = null,
@@ -21334,7 +21348,7 @@ function DataList({
21334
21348
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "error", children: error.message }) });
21335
21349
  }
21336
21350
  if (data.length === 0) {
21337
- const emptyNode = /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: t("empty.noItems") }) });
21351
+ const emptyNode = /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: emptyMessage || t("empty.noItems") }) });
21338
21352
  return dnd.enabled ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: dnd.wrapContainer(emptyNode) }) : emptyNode;
21339
21353
  }
21340
21354
  const gapClass = {
@@ -21350,51 +21364,93 @@ function DataList({
21350
21364
  const items2 = [...data];
21351
21365
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
21352
21366
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
21353
- return /* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React74__namespace.default.Fragment, { children: [
21354
- group.label && /* @__PURE__ */ jsxRuntime.jsx(exports.Divider, { label: group.label, className: "my-2" }),
21355
- group.items.map((itemData, index) => {
21356
- const id = itemData.id || `${gi}-${index}`;
21357
- const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
21358
- const isSent = Boolean(currentUser && sender === currentUser);
21359
- const content = getNestedValue(itemData, contentField);
21360
- const timestampField = fieldDefs.find((f3) => f3.format === "date");
21361
- const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
21362
- return /* @__PURE__ */ jsxRuntime.jsx(
21363
- exports.Box,
21364
- {
21365
- className: cn(
21366
- "flex px-4",
21367
- isSent ? "justify-end" : "justify-start"
21368
- ),
21369
- children: /* @__PURE__ */ jsxRuntime.jsxs(
21370
- exports.Box,
21371
- {
21372
- className: cn(
21373
- "max-w-[75%] px-4 py-2",
21374
- isSent ? "bg-primary text-primary-foreground rounded-2xl rounded-br-sm" : "bg-muted text-foreground rounded-2xl rounded-bl-sm"
21375
- ),
21376
- children: [
21377
- !isSent && senderField && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
21378
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
21379
- timestamp != null ? /* @__PURE__ */ jsxRuntime.jsx(
21380
- exports.Typography,
21381
- {
21382
- variant: "caption",
21383
- className: cn(
21384
- "mt-1 text-xs",
21385
- isSent ? "opacity-70" : "text-muted-foreground"
21386
- ),
21387
- children: formatDate3(timestamp)
21388
- }
21389
- ) : null
21390
- ]
21391
- }
21392
- )
21393
- },
21394
- id
21395
- );
21396
- })
21397
- ] }, gi)) });
21367
+ const senderLabel = (itemData, raw) => {
21368
+ if (!senderLabelField) return raw;
21369
+ const v = getNestedValue(itemData, senderLabelField);
21370
+ return v === void 0 || v === null || v === "" ? raw : String(v);
21371
+ };
21372
+ return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", className: cn("py-2", className), children: [
21373
+ groups2.map((group, gi) => /* @__PURE__ */ jsxRuntime.jsxs(React74__namespace.default.Fragment, { children: [
21374
+ group.label && /* @__PURE__ */ jsxRuntime.jsx(exports.Divider, { label: group.label, className: "my-2" }),
21375
+ group.items.map((itemData, index) => {
21376
+ const id = itemData.id || `${gi}-${index}`;
21377
+ const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
21378
+ const isSent = Boolean(currentUser && sender === currentUser);
21379
+ const content = getNestedValue(itemData, contentField);
21380
+ const timestampField = fieldDefs.find((f3) => f3.format === "date");
21381
+ const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
21382
+ const metaFields = fieldDefs.filter(
21383
+ (f3) => f3.name !== contentField && f3.name !== timestampField?.name
21384
+ );
21385
+ return /* @__PURE__ */ jsxRuntime.jsx(
21386
+ exports.Box,
21387
+ {
21388
+ "data-entity-row": true,
21389
+ "data-entity-id": id,
21390
+ onClick: itemClickEvent ? handleRowClick(itemData) : void 0,
21391
+ className: cn(
21392
+ "flex px-4 group/rowactions",
21393
+ itemClickEvent && "cursor-pointer",
21394
+ isSent ? "justify-end" : "justify-start"
21395
+ ),
21396
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
21397
+ exports.Box,
21398
+ {
21399
+ className: cn(
21400
+ "max-w-[75%] px-4 py-2",
21401
+ isSent ? "bg-primary text-primary-foreground rounded-2xl rounded-br-sm" : "bg-muted text-foreground rounded-2xl rounded-bl-sm"
21402
+ ),
21403
+ children: [
21404
+ !isSent && senderField && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "font-semibold mb-0.5", children: senderLabel(itemData, sender) }),
21405
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
21406
+ metaFields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", className: "mt-1 flex-wrap", children: metaFields.map((f3) => {
21407
+ const v = getNestedValue(itemData, f3.name);
21408
+ if (v === void 0 || v === null || v === "") return null;
21409
+ return f3.variant === "badge" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: statusVariant3(String(v)), children: String(v) }, f3.name) : /* @__PURE__ */ jsxRuntime.jsx(
21410
+ exports.Typography,
21411
+ {
21412
+ variant: "caption",
21413
+ className: cn("text-xs", isSent ? "opacity-70" : "text-muted-foreground"),
21414
+ children: formatValue2(v, f3.format)
21415
+ },
21416
+ f3.name
21417
+ );
21418
+ }) }),
21419
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", className: "mt-1 items-center justify-between", children: [
21420
+ timestamp != null ? /* @__PURE__ */ jsxRuntime.jsx(
21421
+ exports.Typography,
21422
+ {
21423
+ variant: "caption",
21424
+ className: cn("text-xs", isSent ? "opacity-70" : "text-muted-foreground"),
21425
+ children: formatDate(timestamp)
21426
+ }
21427
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
21428
+ renderItemActions(itemData)
21429
+ ] })
21430
+ ]
21431
+ }
21432
+ )
21433
+ },
21434
+ id
21435
+ );
21436
+ })
21437
+ ] }, gi)),
21438
+ hasMoreLocal && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
21439
+ exports.Button,
21440
+ {
21441
+ variant: "ghost",
21442
+ size: "sm",
21443
+ onClick: () => setVisibleCount((prev) => prev + (pageSize || 5)),
21444
+ children: [
21445
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
21446
+ t("common.showMore"),
21447
+ " (",
21448
+ t("common.remaining", { count: allData.length - visibleCount }),
21449
+ ")"
21450
+ ]
21451
+ }
21452
+ ) })
21453
+ ] });
21398
21454
  }
21399
21455
  const items = [...data];
21400
21456
  const groups = groupBy ? groupData(items, groupBy) : [{ label: "", items }];
@@ -21543,11 +21599,12 @@ function DataList({
21543
21599
  )
21544
21600
  );
21545
21601
  }
21546
- var dataListLog, listLookStyles;
21602
+ var dataListLog, fieldLabel3, listLookStyles;
21547
21603
  var init_DataList = __esm({
21548
21604
  "components/core/molecules/DataList.tsx"() {
21549
21605
  "use client";
21550
21606
  init_cn();
21607
+ init_format();
21551
21608
  init_getNestedValue();
21552
21609
  init_useEventBus();
21553
21610
  init_Box();
@@ -21562,6 +21619,7 @@ var init_DataList = __esm({
21562
21619
  init_Menu();
21563
21620
  init_useDataDnd();
21564
21621
  dataListLog = logger.createLogger("almadar:ui:data-list");
21622
+ fieldLabel3 = humanizeFieldName;
21565
21623
  listLookStyles = {
21566
21624
  dense: "[&_[data-entity-row]>div]:!py-1 [&_[data-entity-row]>div]:!px-3",
21567
21625
  spacious: "[&_[data-entity-row]>div]:!py-5 [&_[data-entity-row]>div]:!px-8",
@@ -26030,7 +26088,7 @@ var init_ScoreDisplay = __esm({
26030
26088
  ScoreDisplay.displayName = "ScoreDisplay";
26031
26089
  }
26032
26090
  });
26033
- function formatTime(seconds, format) {
26091
+ function formatTime2(seconds, format) {
26034
26092
  const clamped = Math.max(0, Math.floor(seconds));
26035
26093
  if (format === "ss") {
26036
26094
  return `${clamped}s`;
@@ -26067,7 +26125,7 @@ function TimerDisplay({
26067
26125
  ),
26068
26126
  children: [
26069
26127
  iconAsset && /* @__PURE__ */ jsxRuntime.jsx(GameIcon, { assetUrl: iconAsset, icon: "image", size: 16, className: "w-4 h-4 object-contain flex-shrink-0" }),
26070
- formatTime(seconds, format)
26128
+ formatTime2(seconds, format)
26071
26129
  ]
26072
26130
  }
26073
26131
  );
@@ -26135,6 +26193,210 @@ var init_DialogueBubble = __esm({
26135
26193
  DialogueBubble.displayName = "DialogueBubble";
26136
26194
  }
26137
26195
  });
26196
+ function SvgStage({
26197
+ cols,
26198
+ rows: rows2,
26199
+ tileSize = 32,
26200
+ background = "var(--color-background)",
26201
+ tileClickEvent,
26202
+ tileHoverEvent,
26203
+ tileLeaveEvent,
26204
+ keyMap,
26205
+ keyUpMap,
26206
+ className,
26207
+ children
26208
+ }) {
26209
+ const eventBus = useEventBus();
26210
+ const svgRef = React74.useRef(null);
26211
+ const pointerDownRef = React74.useRef(null);
26212
+ const cellFromClient = React74.useCallback((clientX, clientY) => {
26213
+ const svg = svgRef.current;
26214
+ if (!svg) return null;
26215
+ const rect = svg.getBoundingClientRect();
26216
+ if (rect.width === 0 || rect.height === 0) return null;
26217
+ const vbW = cols * tileSize;
26218
+ const vbH = rows2 * tileSize;
26219
+ const meet = Math.min(rect.width / vbW, rect.height / vbH);
26220
+ const offsetX = (rect.width - vbW * meet) / 2;
26221
+ const offsetY = (rect.height - vbH * meet) / 2;
26222
+ const svgX = (clientX - rect.left - offsetX) / meet;
26223
+ const svgY = (clientY - rect.top - offsetY) / meet;
26224
+ return {
26225
+ x: Math.min(Math.max(Math.floor(svgX / tileSize), 0), cols - 1),
26226
+ y: Math.min(Math.max(Math.floor(svgY / tileSize), 0), rows2 - 1)
26227
+ };
26228
+ }, [cols, rows2, tileSize]);
26229
+ const handlePointerDown = React74.useCallback((e) => {
26230
+ pointerDownRef.current = { clientX: e.clientX, clientY: e.clientY };
26231
+ }, []);
26232
+ const handlePointerUp = React74.useCallback((e) => {
26233
+ const down = pointerDownRef.current;
26234
+ pointerDownRef.current = null;
26235
+ if (!tileClickEvent) return;
26236
+ if (down && Math.hypot(e.clientX - down.clientX, e.clientY - down.clientY) > 5) return;
26237
+ const cell = cellFromClient(e.clientX, e.clientY);
26238
+ if (cell) eventBus.emit(`UI:${tileClickEvent}`, cell);
26239
+ }, [cellFromClient, tileClickEvent, eventBus]);
26240
+ const handlePointerMove = React74.useCallback((e) => {
26241
+ if (!tileHoverEvent) return;
26242
+ const cell = cellFromClient(e.clientX, e.clientY);
26243
+ if (cell) eventBus.emit(`UI:${tileHoverEvent}`, cell);
26244
+ }, [cellFromClient, tileHoverEvent, eventBus]);
26245
+ const handlePointerLeave = React74.useCallback(() => {
26246
+ pointerDownRef.current = null;
26247
+ if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
26248
+ }, [tileLeaveEvent, eventBus]);
26249
+ React74.useEffect(() => {
26250
+ if (!keyMap && !keyUpMap) return;
26251
+ const onDown = (e) => {
26252
+ const ev = keyMap?.[e.code];
26253
+ if (ev) {
26254
+ eventBus.emit(`UI:${ev}`, {});
26255
+ e.preventDefault();
26256
+ }
26257
+ };
26258
+ const onUp = (e) => {
26259
+ const ev = keyUpMap?.[e.code];
26260
+ if (ev) eventBus.emit(`UI:${ev}`, {});
26261
+ };
26262
+ window.addEventListener("keydown", onDown);
26263
+ window.addEventListener("keyup", onUp);
26264
+ return () => {
26265
+ window.removeEventListener("keydown", onDown);
26266
+ window.removeEventListener("keyup", onUp);
26267
+ };
26268
+ }, [keyMap, keyUpMap, eventBus]);
26269
+ React74.useEffect(() => {
26270
+ if (!keyMap && !keyUpMap) return;
26271
+ svgRef.current?.focus();
26272
+ }, [keyMap, keyUpMap]);
26273
+ const stageContext = React74.useMemo(() => ({ tileSize }), [tileSize]);
26274
+ return /* @__PURE__ */ jsxRuntime.jsxs(
26275
+ "svg",
26276
+ {
26277
+ ref: svgRef,
26278
+ "data-testid": "svg-stage",
26279
+ viewBox: `0 0 ${cols * tileSize} ${rows2 * tileSize}`,
26280
+ preserveAspectRatio: "xMidYMid meet",
26281
+ className: cn("block h-full w-full", className),
26282
+ tabIndex: keyMap || keyUpMap ? 0 : void 0,
26283
+ onPointerDown: handlePointerDown,
26284
+ onPointerMove: handlePointerMove,
26285
+ onPointerUp: handlePointerUp,
26286
+ onPointerLeave: handlePointerLeave,
26287
+ children: [
26288
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: cols * tileSize, height: rows2 * tileSize, fill: background }),
26289
+ /* @__PURE__ */ jsxRuntime.jsx(exports.SvgStageContext.Provider, { value: stageContext, children })
26290
+ ]
26291
+ }
26292
+ );
26293
+ }
26294
+ exports.SvgStageContext = void 0;
26295
+ var init_SvgStage = __esm({
26296
+ "components/game/molecules/SvgStage.tsx"() {
26297
+ "use client";
26298
+ init_cn();
26299
+ init_useEventBus();
26300
+ exports.SvgStageContext = React74__namespace.createContext({ tileSize: 1 });
26301
+ SvgStage.displayName = "SvgStage";
26302
+ }
26303
+ });
26304
+ function SvgDrawShape({
26305
+ shape,
26306
+ x,
26307
+ y,
26308
+ width,
26309
+ height,
26310
+ radius,
26311
+ radiusY,
26312
+ points,
26313
+ d,
26314
+ x2,
26315
+ y2,
26316
+ fill,
26317
+ stroke,
26318
+ strokeWidth,
26319
+ opacity,
26320
+ className
26321
+ }) {
26322
+ const { tileSize } = React74.useContext(exports.SvgStageContext);
26323
+ const cell = (v) => v === void 0 ? void 0 : v * tileSize;
26324
+ const paint = {
26325
+ fill: fill ?? (stroke === void 0 ? "var(--color-primary)" : "none"),
26326
+ stroke,
26327
+ strokeWidth,
26328
+ opacity,
26329
+ className
26330
+ };
26331
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${x * tileSize} ${y * tileSize})`, children: [
26332
+ shape === "rect" && /* @__PURE__ */ jsxRuntime.jsx("rect", { width: cell(width), height: cell(height), ...paint }),
26333
+ shape === "circle" && /* @__PURE__ */ jsxRuntime.jsx("circle", { r: cell(radius), ...paint }),
26334
+ shape === "ellipse" && /* @__PURE__ */ jsxRuntime.jsx("ellipse", { rx: cell(radius), ry: cell(radiusY ?? radius), ...paint }),
26335
+ shape === "polygon" && /* @__PURE__ */ jsxRuntime.jsx("polygon", { points, ...paint }),
26336
+ shape === "polyline" && /* @__PURE__ */ jsxRuntime.jsx("polyline", { points, ...paint }),
26337
+ shape === "path" && /* @__PURE__ */ jsxRuntime.jsx("path", { d, ...paint }),
26338
+ shape === "line" && /* @__PURE__ */ jsxRuntime.jsx("line", { x2: cell(x2), y2: cell(y2), ...paint })
26339
+ ] });
26340
+ }
26341
+ var init_SvgDrawShape = __esm({
26342
+ "components/game/atoms/SvgDrawShape.tsx"() {
26343
+ "use client";
26344
+ init_SvgStage();
26345
+ SvgDrawShape.displayName = "SvgDrawShape";
26346
+ }
26347
+ });
26348
+ function SvgDrawGroup({
26349
+ x = 0,
26350
+ y = 0,
26351
+ scale,
26352
+ rotate,
26353
+ opacity,
26354
+ className,
26355
+ children
26356
+ }) {
26357
+ const { tileSize } = React74.useContext(exports.SvgStageContext);
26358
+ const transforms = [`translate(${x * tileSize} ${y * tileSize})`];
26359
+ if (rotate !== void 0) transforms.push(`rotate(${rotate})`);
26360
+ if (scale !== void 0) transforms.push(`scale(${scale})`);
26361
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { transform: transforms.join(" "), opacity, className, children });
26362
+ }
26363
+ var init_SvgDrawGroup = __esm({
26364
+ "components/game/atoms/SvgDrawGroup.tsx"() {
26365
+ "use client";
26366
+ init_SvgStage();
26367
+ SvgDrawGroup.displayName = "SvgDrawGroup";
26368
+ }
26369
+ });
26370
+ function SvgDrawText({
26371
+ x,
26372
+ y,
26373
+ text,
26374
+ size = 12,
26375
+ fill = "var(--color-foreground)",
26376
+ anchor = "middle",
26377
+ className
26378
+ }) {
26379
+ const { tileSize } = React74.useContext(exports.SvgStageContext);
26380
+ return /* @__PURE__ */ jsxRuntime.jsx(
26381
+ "text",
26382
+ {
26383
+ x: x * tileSize,
26384
+ y: y * tileSize,
26385
+ fontSize: size,
26386
+ fill,
26387
+ textAnchor: anchor,
26388
+ className,
26389
+ children: text
26390
+ }
26391
+ );
26392
+ }
26393
+ var init_SvgDrawText = __esm({
26394
+ "components/game/atoms/SvgDrawText.tsx"() {
26395
+ "use client";
26396
+ init_SvgStage();
26397
+ SvgDrawText.displayName = "SvgDrawText";
26398
+ }
26399
+ });
26138
26400
  function StatBadge({
26139
26401
  assetUrl,
26140
26402
  iconUrl,
@@ -26625,6 +26887,32 @@ var init_StateGraph = __esm({
26625
26887
  init_TransitionArrow();
26626
26888
  }
26627
26889
  });
26890
+ function SvgDrawShapeLayer({
26891
+ items,
26892
+ fill,
26893
+ stroke,
26894
+ strokeWidth,
26895
+ opacity
26896
+ }) {
26897
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { children: items.map(({ id, ...shape }) => /* @__PURE__ */ jsxRuntime.jsx(
26898
+ SvgDrawShape,
26899
+ {
26900
+ ...shape,
26901
+ fill: shape.fill ?? fill,
26902
+ stroke: shape.stroke ?? stroke,
26903
+ strokeWidth: shape.strokeWidth ?? strokeWidth,
26904
+ opacity: shape.opacity ?? opacity
26905
+ },
26906
+ id
26907
+ )) });
26908
+ }
26909
+ var init_SvgDrawShapeLayer = __esm({
26910
+ "components/game/molecules/SvgDrawShapeLayer.tsx"() {
26911
+ "use client";
26912
+ init_SvgDrawShape();
26913
+ SvgDrawShapeLayer.displayName = "SvgDrawShapeLayer";
26914
+ }
26915
+ });
26628
26916
  function unitAtlasUrl(unit) {
26629
26917
  return unit.spriteSheet?.url ?? null;
26630
26918
  }
@@ -28092,6 +28380,9 @@ var init_molecules = __esm({
28092
28380
  init_TimerDisplay();
28093
28381
  init_DialogueBubble();
28094
28382
  init_ChoiceButton();
28383
+ init_SvgDrawShape();
28384
+ init_SvgDrawGroup();
28385
+ init_SvgDrawText();
28095
28386
  init_ControlGrid();
28096
28387
  init_StatBadge();
28097
28388
  init_GameHud();
@@ -28099,6 +28390,8 @@ var init_molecules = __esm({
28099
28390
  init_StateGraph();
28100
28391
  init_Canvas2D();
28101
28392
  init_Canvas();
28393
+ init_SvgDrawShapeLayer();
28394
+ init_SvgStage();
28102
28395
  init_useUnitSpriteAtlas();
28103
28396
  init_GameAudioToggle();
28104
28397
  init_useGameAudio();
@@ -28716,13 +29009,13 @@ var init_MapView = __esm({
28716
29009
  shadowSize: [41, 41]
28717
29010
  });
28718
29011
  L.Marker.prototype.options.icon = defaultIcon;
28719
- const { useEffect: useEffect65, useRef: useRef63, useCallback: useCallback106, useState: useState102 } = React74__namespace.default;
29012
+ const { useEffect: useEffect66, useRef: useRef64, useCallback: useCallback107, useState: useState102 } = React74__namespace.default;
28720
29013
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
28721
29014
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
28722
29015
  function MapUpdater({ centerLat, centerLng, zoom }) {
28723
29016
  const map = useMap();
28724
- const prevRef = useRef63({ centerLat, centerLng, zoom });
28725
- useEffect65(() => {
29017
+ const prevRef = useRef64({ centerLat, centerLng, zoom });
29018
+ useEffect66(() => {
28726
29019
  const prev = prevRef.current;
28727
29020
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
28728
29021
  map.setView([centerLat, centerLng], zoom);
@@ -28733,7 +29026,7 @@ var init_MapView = __esm({
28733
29026
  }
28734
29027
  function MapClickHandler({ onMapClick }) {
28735
29028
  const map = useMap();
28736
- useEffect65(() => {
29029
+ useEffect66(() => {
28737
29030
  if (!onMapClick) return;
28738
29031
  const handler = (e) => {
28739
29032
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -28762,7 +29055,7 @@ var init_MapView = __esm({
28762
29055
  }) {
28763
29056
  const eventBus = useEventBus2();
28764
29057
  const [clickedPosition, setClickedPosition] = useState102(null);
28765
- const handleMapClick = useCallback106((lat, lng) => {
29058
+ const handleMapClick = useCallback107((lat, lng) => {
28766
29059
  if (showClickedPin) {
28767
29060
  setClickedPosition({ lat, lng });
28768
29061
  }
@@ -28771,7 +29064,7 @@ var init_MapView = __esm({
28771
29064
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
28772
29065
  }
28773
29066
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
28774
- const handleMarkerClick = useCallback106((marker) => {
29067
+ const handleMarkerClick = useCallback107((marker) => {
28775
29068
  onMarkerClick?.(marker);
28776
29069
  if (markerClickEvent) {
28777
29070
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -29571,7 +29864,7 @@ function renderIconInput3(icon, props) {
29571
29864
  return typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, ...props }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, ...props });
29572
29865
  }
29573
29866
  function columnLabel(col) {
29574
- return col.header ?? col.label ?? col.key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
29867
+ return col.header ?? col.label ?? humanizeFieldName(col.key);
29575
29868
  }
29576
29869
  function asFieldValue(v) {
29577
29870
  if (v === void 0 || v === null) return v;
@@ -29590,25 +29883,6 @@ function statusVariant4(value) {
29590
29883
  if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
29591
29884
  return "default";
29592
29885
  }
29593
- function formatCell(value, format) {
29594
- if (value === void 0 || value === null) return "";
29595
- switch (format) {
29596
- case "date": {
29597
- const d = new Date(String(value));
29598
- return isNaN(d.getTime()) ? String(value) : d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
29599
- }
29600
- case "currency":
29601
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
29602
- case "number":
29603
- return typeof value === "number" ? value.toLocaleString() : String(value);
29604
- case "percent":
29605
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
29606
- case "boolean":
29607
- return value ? "Yes" : "No";
29608
- default:
29609
- return String(value);
29610
- }
29611
- }
29612
29886
  function groupData2(items, field) {
29613
29887
  const groups = /* @__PURE__ */ new Map();
29614
29888
  for (const item of items) {
@@ -29654,7 +29928,8 @@ function TableView({
29654
29928
  const { t } = hooks.useTranslate();
29655
29929
  const [visibleCount, setVisibleCount] = React74__namespace.default.useState(pageSize > 0 ? pageSize : Infinity);
29656
29930
  const [localSelected, setLocalSelected] = React74__namespace.default.useState(/* @__PURE__ */ new Set());
29657
- const colDefs = columns ?? fields ?? [];
29931
+ const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
29932
+ const actionDefs = Array.isArray(itemActions) ? itemActions : [];
29658
29933
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
29659
29934
  const dnd = useDataDnd({
29660
29935
  items: allDataRaw,
@@ -29674,6 +29949,23 @@ function TableView({
29674
29949
  const hasRenderProp = typeof children === "function";
29675
29950
  const idField = dndItemIdField ?? "id";
29676
29951
  const isCoarsePointer = useMediaQuery("(pointer: coarse)");
29952
+ React74__namespace.default.useEffect(() => {
29953
+ tableViewLog.debug("render", {
29954
+ rowCount: data.length,
29955
+ colCount: colDefs.length,
29956
+ look,
29957
+ isLoading: Boolean(isLoading),
29958
+ hasError: Boolean(error),
29959
+ dnd: dnd.enabled
29960
+ });
29961
+ if (data.length > 0 && !hasRenderProp && colDefs.length === 0) {
29962
+ tableViewLog.warn("columns-unresolved", {
29963
+ rowCount: data.length,
29964
+ columnsIsArray: Array.isArray(columns),
29965
+ fieldsIsArray: Array.isArray(fields)
29966
+ });
29967
+ }
29968
+ }, [data, colDefs, look, isLoading, error, dnd.enabled, hasRenderProp, columns, fields]);
29677
29969
  const selected = selectedIds ? new Set(selectedIds) : localSelected;
29678
29970
  const emitSelection = (next) => {
29679
29971
  if (!selectedIds) setLocalSelected(next);
@@ -29717,21 +30009,12 @@ function TableView({
29717
30009
  }),
29718
30010
  [colDefs, data]
29719
30011
  );
29720
- if (isLoading) {
29721
- return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
29722
- }
29723
- if (error) {
29724
- return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "error", children: error.message }) });
29725
- }
29726
- if (data.length === 0) {
29727
- const emptyNode = /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: emptyMessage || t("empty.noItems") }) });
29728
- return dnd.enabled ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: dnd.wrapContainer(emptyNode) }) : emptyNode;
29729
- }
30012
+ const statusNode = isLoading ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: t("loading.items") }) }) : error ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "error", children: error.message }) }) : data.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", color: "secondary", children: emptyMessage || t("empty.noItems") }) }) : null;
29730
30013
  const lk = LOOKS[look];
29731
- const hasActions = Boolean(itemActions && itemActions.length > 0);
30014
+ const hasActions = actionDefs.length > 0;
29732
30015
  const effectiveMaxInline = isCoarsePointer ? 0 : maxInlineActions;
29733
- const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(itemActions.length, effectiveMaxInline) : itemActions.length : 0;
29734
- const hasOverflowActions = hasActions && effectiveMaxInline != null && itemActions.length > effectiveMaxInline;
30016
+ const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(actionDefs.length, effectiveMaxInline) : actionDefs.length : 0;
30017
+ const hasOverflowActions = hasActions && effectiveMaxInline != null && actionDefs.length > effectiveMaxInline;
29735
30018
  const actionsTrack = hasActions ? `${inlineActionCount * 6 + (hasOverflowActions ? 3 : 0)}rem` : null;
29736
30019
  const gridTemplateColumns = [
29737
30020
  selectable ? "auto" : null,
@@ -29819,11 +30102,11 @@ function TableView({
29819
30102
  col.className
29820
30103
  );
29821
30104
  if (col.format === "badge" && raw != null && raw !== "") {
29822
- return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: statusVariant4(String(raw)), size: "sm", className: "whitespace-nowrap", children: String(raw) }) }, col.key);
30105
+ return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: statusVariant4(String(raw)), size: "sm", className: "whitespace-nowrap", children: humanizeEnumValue(String(raw)) }) }, col.key);
29823
30106
  }
29824
30107
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
29825
30108
  }),
29826
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
30109
+ hasActions && /* @__PURE__ */ jsxRuntime.jsxs(
29827
30110
  exports.HStack,
29828
30111
  {
29829
30112
  gap: "xs",
@@ -29835,7 +30118,7 @@ function TableView({
29835
30118
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
29836
30119
  ),
29837
30120
  children: [
29838
- (effectiveMaxInline != null ? itemActions.slice(0, effectiveMaxInline) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
30121
+ (effectiveMaxInline != null ? actionDefs.slice(0, effectiveMaxInline) : actionDefs).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
29839
30122
  exports.Button,
29840
30123
  {
29841
30124
  variant: action.variant === "primary" ? "primary" : "ghost",
@@ -29851,12 +30134,12 @@ function TableView({
29851
30134
  },
29852
30135
  i
29853
30136
  )),
29854
- effectiveMaxInline != null && itemActions.length > effectiveMaxInline && /* @__PURE__ */ jsxRuntime.jsx(
30137
+ effectiveMaxInline != null && actionDefs.length > effectiveMaxInline && /* @__PURE__ */ jsxRuntime.jsx(
29855
30138
  exports.Menu,
29856
30139
  {
29857
30140
  position: "bottom-end",
29858
30141
  trigger: /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "more-horizontal", size: "xs" }) }),
29859
- items: itemActions.slice(effectiveMaxInline).map((action) => ({
30142
+ items: actionDefs.slice(effectiveMaxInline).map((action) => ({
29860
30143
  label: action.label,
29861
30144
  icon: action.icon,
29862
30145
  event: action.event,
@@ -29883,15 +30166,16 @@ function TableView({
29883
30166
  group.label && /* @__PURE__ */ jsxRuntime.jsx(exports.Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
29884
30167
  group.items.map((row) => renderRow(row, runningIndex++))
29885
30168
  ] }, gi)) });
30169
+ const showHeader = colDefs.length > 0 || hasRenderProp;
29886
30170
  return /* @__PURE__ */ jsxRuntime.jsxs(
29887
30171
  exports.Box,
29888
30172
  {
29889
30173
  role: "table",
29890
30174
  className: cn("w-full text-sm", className),
29891
30175
  children: [
29892
- header,
29893
- dnd.wrapContainer(body),
29894
- hasMore && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "ghost", size: "sm", onClick: () => setVisibleCount((p) => p + (pageSize || 5)), children: [
30176
+ showHeader && header,
30177
+ dnd.wrapContainer(statusNode ? /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { role: "rowgroup", children: statusNode }) : body),
30178
+ !statusNode && hasMore && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "ghost", size: "sm", onClick: () => setVisibleCount((p) => p + (pageSize || 5)), children: [
29895
30179
  /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
29896
30180
  t("common.showMore"),
29897
30181
  " (",
@@ -29902,11 +30186,12 @@ function TableView({
29902
30186
  }
29903
30187
  );
29904
30188
  }
29905
- var MAX_MEASURED_COL_CH, BADGE_CHROME_CH, alignClass, weightClass, LOOKS;
30189
+ var tableViewLog, formatCell, MAX_MEASURED_COL_CH, BADGE_CHROME_CH, alignClass, weightClass, LOOKS;
29906
30190
  var init_TableView = __esm({
29907
30191
  "components/core/molecules/TableView.tsx"() {
29908
30192
  "use client";
29909
30193
  init_cn();
30194
+ init_format();
29910
30195
  init_getNestedValue();
29911
30196
  init_useEventBus();
29912
30197
  init_useMediaQuery();
@@ -29920,7 +30205,8 @@ var init_TableView = __esm({
29920
30205
  init_Divider();
29921
30206
  init_Menu();
29922
30207
  init_useDataDnd();
29923
- logger.createLogger("almadar:ui:table-view");
30208
+ tableViewLog = logger.createLogger("almadar:ui:table-view");
30209
+ formatCell = (value, format) => formatValue(value, format);
29924
30210
  MAX_MEASURED_COL_CH = 32;
29925
30211
  BADGE_CHROME_CH = 4;
29926
30212
  alignClass = {
@@ -37304,6 +37590,7 @@ var init_GraphCanvas = __esm({
37304
37590
  title,
37305
37591
  nodes: propNodes = NO_NODES,
37306
37592
  edges: propEdges = NO_EDGES,
37593
+ proposedEdges = NO_EDGES,
37307
37594
  similarity: propSimilarity = NO_SIM,
37308
37595
  height = 400,
37309
37596
  showLabels = true,
@@ -37311,6 +37598,7 @@ var init_GraphCanvas = __esm({
37311
37598
  draggable = true,
37312
37599
  actions,
37313
37600
  onNodeClick,
37601
+ onMarkClick,
37314
37602
  onNodeDoubleClick,
37315
37603
  onBadgeClick,
37316
37604
  nodeClickEvent,
@@ -37339,6 +37627,18 @@ var init_GraphCanvas = __esm({
37339
37627
  const laidOutRef = React74.useRef(false);
37340
37628
  const [, forceUpdate] = React74.useState(0);
37341
37629
  const [logicalW, setLogicalW] = React74.useState(800);
37630
+ const hasProposed = React74.useMemo(() => propNodes.some((n) => n.mark?.kind === "proposed"), [propNodes]);
37631
+ const [pulseTick, setPulseTick] = React74.useState(0);
37632
+ React74.useEffect(() => {
37633
+ if (!hasProposed) return;
37634
+ let raf = 0;
37635
+ const loop = () => {
37636
+ setPulseTick((t2) => (t2 + 1) % 1e6);
37637
+ raf = requestAnimationFrame(loop);
37638
+ };
37639
+ raf = requestAnimationFrame(loop);
37640
+ return () => cancelAnimationFrame(raf);
37641
+ }, [hasProposed]);
37342
37642
  React74.useEffect(() => {
37343
37643
  const canvas = canvasRef.current;
37344
37644
  if (!canvas || typeof ResizeObserver === "undefined") return;
@@ -37640,18 +37940,38 @@ var init_GraphCanvas = __esm({
37640
37940
  }
37641
37941
  }
37642
37942
  ctx.globalAlpha = 1;
37943
+ ctx.setLineDash([4, 4]);
37944
+ for (const edge of proposedEdges) {
37945
+ const source = nodes.find((n) => n.id === edge.source);
37946
+ const target = nodes.find((n) => n.id === edge.target);
37947
+ if (!source || !target) continue;
37948
+ ctx.globalAlpha = 0.4;
37949
+ ctx.beginPath();
37950
+ ctx.moveTo(source.x, source.y);
37951
+ ctx.lineTo(target.x, target.y);
37952
+ ctx.strokeStyle = edge.color || mutedColor;
37953
+ ctx.lineWidth = 1;
37954
+ ctx.stroke();
37955
+ }
37956
+ ctx.setLineDash([]);
37957
+ ctx.globalAlpha = 1;
37643
37958
  for (const node of nodes) {
37644
37959
  const size = node.size || 8;
37645
37960
  const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
37646
37961
  const isHovered = hoveredNode === node.id;
37647
37962
  const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
37648
- ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
37963
+ const mark = node.mark;
37964
+ ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : mark?.kind === "proposed" ? 0.55 : 1;
37649
37965
  const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
37650
37966
  ctx.beginPath();
37651
37967
  ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
37652
- ctx.fillStyle = color;
37968
+ ctx.fillStyle = mark?.kind === "proposed" ? mutedColor : color;
37653
37969
  ctx.fill();
37654
- if (isSelected) {
37970
+ if (mark?.kind === "proposed") {
37971
+ ctx.setLineDash([3, 3]);
37972
+ ctx.strokeStyle = resolveColor3(mark.tint ?? "var(--color-warning)", canvas);
37973
+ ctx.lineWidth = 1.5;
37974
+ } else if (isSelected) {
37655
37975
  ctx.strokeStyle = accentColor;
37656
37976
  ctx.lineWidth = 3;
37657
37977
  } else {
@@ -37659,6 +37979,28 @@ var init_GraphCanvas = __esm({
37659
37979
  ctx.lineWidth = isHovered ? 2 : 1;
37660
37980
  }
37661
37981
  ctx.stroke();
37982
+ ctx.setLineDash([]);
37983
+ if (mark?.kind === "suggested") {
37984
+ ctx.beginPath();
37985
+ ctx.arc(node.x, node.y, radius + 3, 0, Math.PI * 2);
37986
+ ctx.strokeStyle = accentColor;
37987
+ ctx.lineWidth = 2;
37988
+ ctx.stroke();
37989
+ ctx.beginPath();
37990
+ ctx.arc(node.x + radius * 0.7, node.y - radius * 0.7, 2.5, 0, Math.PI * 2);
37991
+ ctx.fillStyle = accentColor;
37992
+ ctx.fill();
37993
+ } else if (mark?.kind === "proposed") {
37994
+ const phase = pulseTick % 60 / 60;
37995
+ const baseAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 0.55;
37996
+ ctx.globalAlpha = baseAlpha * (0.4 + 0.4 * (1 - Math.abs(phase * 2 - 1)));
37997
+ ctx.beginPath();
37998
+ ctx.arc(node.x, node.y, radius + 6 + Math.sin(phase * Math.PI * 2) * 3, 0, Math.PI * 2);
37999
+ ctx.strokeStyle = resolveColor3(mark.tint ?? "var(--color-warning)", canvas);
38000
+ ctx.lineWidth = 1.5;
38001
+ ctx.stroke();
38002
+ ctx.globalAlpha = baseAlpha;
38003
+ }
37662
38004
  if (showLabels && node.label) {
37663
38005
  const displayLabel = truncateLabel(node.label);
37664
38006
  ctx.font = `${isSelected || isHovered ? "700" : "600"} 12px ${fontFamily}`;
@@ -37793,11 +38135,15 @@ var init_GraphCanvas = __esm({
37793
38135
  return;
37794
38136
  }
37795
38137
  }
38138
+ if (node.mark && onMarkClick) {
38139
+ onMarkClick(node);
38140
+ return;
38141
+ }
37796
38142
  handleNodeClick(node);
37797
38143
  }
37798
38144
  }
37799
38145
  },
37800
- [toCoords, nodeAt, handleNodeClick, onBadgeClick, selectedNodeId]
38146
+ [toCoords, nodeAt, handleNodeClick, onBadgeClick, onMarkClick, selectedNodeId]
37801
38147
  );
37802
38148
  const handlePointerLeave = React74.useCallback(() => {
37803
38149
  setHoveredNode(null);
@@ -38545,9 +38891,6 @@ var init_types2 = __esm({
38545
38891
  };
38546
38892
  }
38547
38893
  });
38548
- function humanizeFieldName(name) {
38549
- return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\b([A-Z])([A-Z]+)\b/g, (_, first, rest) => first + rest.toLowerCase()).trim();
38550
- }
38551
38894
  function normalizeColumns(columns) {
38552
38895
  return columns.map((col) => {
38553
38896
  if (typeof col === "string") {
@@ -38972,6 +39315,7 @@ var init_DataTable = __esm({
38972
39315
  "components/core/organisms/DataTable.tsx"() {
38973
39316
  "use client";
38974
39317
  init_cn();
39318
+ init_format();
38975
39319
  init_getNestedValue();
38976
39320
  init_atoms();
38977
39321
  init_Box();
@@ -39024,9 +39368,6 @@ function getBadgeVariant(fieldName, value) {
39024
39368
  }
39025
39369
  return "default";
39026
39370
  }
39027
- function formatFieldLabel(fieldName) {
39028
- return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
39029
- }
39030
39371
  function formatFieldValue2(value, fieldName) {
39031
39372
  if (typeof value === "number") {
39032
39373
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
@@ -39154,7 +39495,7 @@ function buildFieldTypeMap(fields) {
39154
39495
  }
39155
39496
  return map;
39156
39497
  }
39157
- var ReactMarkdown2; exports.DetailPanel = void 0;
39498
+ var formatFieldLabel, ReactMarkdown2; exports.DetailPanel = void 0;
39158
39499
  var init_DetailPanel = __esm({
39159
39500
  "components/core/organisms/DetailPanel.tsx"() {
39160
39501
  "use client";
@@ -39166,8 +39507,10 @@ var init_DetailPanel = __esm({
39166
39507
  init_ErrorState();
39167
39508
  init_EmptyState();
39168
39509
  init_cn();
39510
+ init_format();
39169
39511
  init_getNestedValue();
39170
39512
  init_useEventBus();
39513
+ formatFieldLabel = humanizeFieldName;
39171
39514
  ReactMarkdown2 = React74.lazy(() => import('react-markdown'));
39172
39515
  exports.DetailPanel = ({
39173
39516
  title: propTitle,
@@ -40696,7 +41039,7 @@ function formatValue3(value, fieldName) {
40696
41039
  return String(value);
40697
41040
  }
40698
41041
  function formatFieldLabel2(fieldName) {
40699
- return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
41042
+ return humanizeFieldName(fieldName).replace(/\sId$/, "").trim();
40700
41043
  }
40701
41044
  var STATUS_STYLES, StatusBadge, ProgressIndicator; exports.List = void 0;
40702
41045
  var init_List = __esm({
@@ -40708,6 +41051,7 @@ var init_List = __esm({
40708
41051
  init_EmptyState();
40709
41052
  init_LoadingState();
40710
41053
  init_cn();
41054
+ init_format();
40711
41055
  init_getNestedValue();
40712
41056
  init_useEventBus();
40713
41057
  init_types2();
@@ -42169,7 +42513,7 @@ function TicksTab({ ticks: ticks2 }) {
42169
42513
  }
42170
42514
  );
42171
42515
  }
42172
- const formatTime2 = (ms) => {
42516
+ const formatTime3 = (ms) => {
42173
42517
  if (ms === 0) return "never";
42174
42518
  const seconds = Math.floor((Date.now() - ms) / 1e3);
42175
42519
  if (seconds < 1) return "just now";
@@ -42195,7 +42539,7 @@ function TicksTab({ ticks: ticks2 }) {
42195
42539
  tick.executionTime.toFixed(1),
42196
42540
  "ms exec"
42197
42541
  ] }),
42198
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatTime2(tick.lastRun) })
42542
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatTime3(tick.lastRun) })
42199
42543
  ] }),
42200
42544
  tick.guardName && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.Badge, { variant: tick.guardPassed ? "success" : "danger", size: "sm", children: [
42201
42545
  tick.guardName,
@@ -42319,7 +42663,7 @@ function EventFlowTab({ events: events2 }) {
42319
42663
  if (filter === "all") return events2;
42320
42664
  return events2.filter((e) => e.type === filter);
42321
42665
  }, [events2, filter]);
42322
- const formatTime2 = (timestamp) => {
42666
+ const formatTime3 = (timestamp) => {
42323
42667
  const date = new Date(timestamp);
42324
42668
  return date.toLocaleTimeString("en-US", {
42325
42669
  hour12: false,
@@ -42395,7 +42739,7 @@ function EventFlowTab({ events: events2 }) {
42395
42739
  {
42396
42740
  className: "flex items-start gap-2 text-xs py-1 hover:bg-muted/50 rounded px-1",
42397
42741
  children: [
42398
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime2(event.timestamp) }),
42742
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime3(event.timestamp) }),
42399
42743
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: icon }),
42400
42744
  /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant, size: "sm", className: "min-w-[60px] justify-center", children: event.source }),
42401
42745
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground", children: event.message })
@@ -42449,7 +42793,7 @@ function GuardsPanel({ guards }) {
42449
42793
  if (filter === "passed") return guards.filter((g) => g.result);
42450
42794
  return guards.filter((g) => !g.result);
42451
42795
  }, [guards, filter]);
42452
- const formatTime2 = (timestamp) => {
42796
+ const formatTime3 = (timestamp) => {
42453
42797
  const date = new Date(timestamp);
42454
42798
  return date.toLocaleTimeString("en-US", {
42455
42799
  hour12: false,
@@ -42464,7 +42808,7 @@ function GuardsPanel({ guards }) {
42464
42808
  /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: guard.result ? "success" : "danger", size: "sm", children: guard.result ? "\u2713" : "\u2717" }),
42465
42809
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", weight: "semibold", className: "text-warning", children: guard.guardName }),
42466
42810
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground", children: guard.context.type === "transition" ? `${guard.context.transitionFrom} \u2192 ${guard.context.transitionTo}` : guard.context.tickName }),
42467
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground ml-auto", children: formatTime2(guard.timestamp) })
42811
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground ml-auto", children: formatTime3(guard.timestamp) })
42468
42812
  ] }),
42469
42813
  content: /* @__PURE__ */ jsxRuntime.jsxs(exports.Stack, { gap: "sm", children: [
42470
42814
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -42625,7 +42969,7 @@ function TransitionTimeline({ transitions }) {
42625
42969
  }
42626
42970
  );
42627
42971
  }
42628
- const formatTime2 = (ts) => {
42972
+ const formatTime3 = (ts) => {
42629
42973
  const d = new Date(ts);
42630
42974
  return d.toLocaleTimeString("en-US", {
42631
42975
  hour12: false,
@@ -42673,7 +43017,7 @@ function TransitionTimeline({ transitions }) {
42673
43017
  ${hasFailedEffects ? "bg-error" : allPassed ? "bg-success" : "bg-muted-foreground"}
42674
43018
  ` }),
42675
43019
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs py-1 px-2", children: [
42676
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime2(trace.timestamp) }),
43020
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime3(trace.timestamp) }),
42677
43021
  /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: "primary", size: "sm", className: "min-w-[60px] justify-center", children: trace.traitName }),
42678
43022
  /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "small", className: "font-mono text-muted-foreground", children: [
42679
43023
  trace.from,
@@ -42748,7 +43092,7 @@ function ServerBridgeTab({ bridge }) {
42748
43092
  }
42749
43093
  );
42750
43094
  }
42751
- const formatTime2 = (ts) => {
43095
+ const formatTime3 = (ts) => {
42752
43096
  if (ts === 0) return t("debug.never");
42753
43097
  const d = new Date(ts);
42754
43098
  return d.toLocaleTimeString("en-US", {
@@ -42791,7 +43135,7 @@ function ServerBridgeTab({ bridge }) {
42791
43135
  StatRow,
42792
43136
  {
42793
43137
  label: t("debug.lastHeartbeat"),
42794
- value: formatTime2(bridge.lastHeartbeat)
43138
+ value: formatTime3(bridge.lastHeartbeat)
42795
43139
  }
42796
43140
  )
42797
43141
  ] })
@@ -44903,7 +45247,7 @@ var init_TeamOrganism = __esm({
44903
45247
  exports.TeamOrganism.displayName = "TeamOrganism";
44904
45248
  }
44905
45249
  });
44906
- function formatDate4(value) {
45250
+ function formatDate2(value) {
44907
45251
  const d = new Date(value);
44908
45252
  if (isNaN(d.getTime())) return value;
44909
45253
  return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
@@ -45035,7 +45379,7 @@ var init_Timeline = __esm({
45035
45379
  /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", className: cn("flex-1 min-w-0", !isLast && "pb-6"), children: [
45036
45380
  /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { justify: "between", align: "start", wrap: true, children: [
45037
45381
  /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", weight: "semibold", children: item.title }),
45038
- item.date && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: formatDate4(item.date) })
45382
+ item.date && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: formatDate2(item.date) })
45039
45383
  ] }),
45040
45384
  item.description && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "secondary", children: item.description }),
45041
45385
  item.tags && item.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: item.tags.map((tag, tagIdx) => /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: "default", children: tag }, tagIdx)) }),
@@ -45341,6 +45685,10 @@ var init_component_registry_generated = __esm({
45341
45685
  init_SubagentTracePanel();
45342
45686
  init_SvgBranch();
45343
45687
  init_SvgConnection();
45688
+ init_SvgDrawGroup();
45689
+ init_SvgDrawShape();
45690
+ init_SvgDrawShapeLayer();
45691
+ init_SvgDrawText();
45344
45692
  init_SvgFlow();
45345
45693
  init_SvgGrid();
45346
45694
  init_SvgLobe();
@@ -45351,6 +45699,7 @@ var init_component_registry_generated = __esm({
45351
45699
  init_SvgRing();
45352
45700
  init_SvgShield();
45353
45701
  init_SvgStack();
45702
+ init_SvgStage();
45354
45703
  init_SwipeableRow();
45355
45704
  init_Switch();
45356
45705
  init_TabbedContainer();
@@ -45612,6 +45961,10 @@ var init_component_registry_generated = __esm({
45612
45961
  "SubagentTracePanel": exports.SubagentTracePanel,
45613
45962
  "SvgBranch": exports.SvgBranch,
45614
45963
  "SvgConnection": exports.SvgConnection,
45964
+ "SvgDrawGroup": SvgDrawGroup,
45965
+ "SvgDrawShape": SvgDrawShape,
45966
+ "SvgDrawShapeLayer": SvgDrawShapeLayer,
45967
+ "SvgDrawText": SvgDrawText,
45615
45968
  "SvgFlow": exports.SvgFlow,
45616
45969
  "SvgGrid": exports.SvgGrid,
45617
45970
  "SvgLobe": exports.SvgLobe,
@@ -45622,6 +45975,7 @@ var init_component_registry_generated = __esm({
45622
45975
  "SvgRing": exports.SvgRing,
45623
45976
  "SvgShield": exports.SvgShield,
45624
45977
  "SvgStack": exports.SvgStack,
45978
+ "SvgStage": SvgStage,
45625
45979
  "SwipeableRow": exports.SwipeableRow,
45626
45980
  "Switch": exports.Switch,
45627
45981
  "TabbedContainer": exports.TabbedContainer,
@@ -45698,7 +46052,7 @@ function enrichFormFields(fields, entityDef) {
45698
46052
  if (entityField) {
45699
46053
  const enriched = {
45700
46054
  name: field,
45701
- label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()),
46055
+ label: humanizeFieldName(field),
45702
46056
  type: entityField.type,
45703
46057
  required: entityField.required ?? false
45704
46058
  };
@@ -45712,7 +46066,7 @@ function enrichFormFields(fields, entityDef) {
45712
46066
  }
45713
46067
  return enriched;
45714
46068
  }
45715
- return { name: field, label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()) };
46069
+ return { name: field, label: humanizeFieldName(field) };
45716
46070
  }
45717
46071
  if (field && typeof field === "object" && !Array.isArray(field) && !React74__namespace.default.isValidElement(field) && !(field instanceof Date)) {
45718
46072
  const obj = field;
@@ -46367,9 +46721,10 @@ function SlotContentRenderer({
46367
46721
  const slotVal = restProps[slotKey];
46368
46722
  if (slotVal === void 0 || slotVal === null) continue;
46369
46723
  if (React74__namespace.default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
46370
- if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
46724
+ const typelessChildren = !Array.isArray(slotVal) && typeof slotVal === "object" && !("type" in slotVal) && Array.isArray(slotVal.children) ? slotVal.children : void 0;
46725
+ if (typelessChildren !== void 0 || Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
46371
46726
  nodeSlotOverrides[slotKey] = renderPatternChildren(
46372
- slotVal,
46727
+ typelessChildren ?? slotVal,
46373
46728
  onDismiss,
46374
46729
  `${content.id}-${slotKey}`,
46375
46730
  `${myPath}.${slotKey}`,
@@ -46548,6 +46903,7 @@ var init_UISlotRenderer = __esm({
46548
46903
  init_useEventBus();
46549
46904
  init_slot_types();
46550
46905
  init_cn();
46906
+ init_format();
46551
46907
  init_ErrorBoundary();
46552
46908
  init_Skeleton();
46553
46909
  init_renderer();
@@ -49136,6 +49492,11 @@ exports.StateGraph = StateGraph;
49136
49492
  exports.StateJsonView = StateJsonView;
49137
49493
  exports.StateNode = StateNode2;
49138
49494
  exports.StatusBar = StatusBar;
49495
+ exports.SvgDrawGroup = SvgDrawGroup;
49496
+ exports.SvgDrawShape = SvgDrawShape;
49497
+ exports.SvgDrawShapeLayer = SvgDrawShapeLayer;
49498
+ exports.SvgDrawText = SvgDrawText;
49499
+ exports.SvgStage = SvgStage;
49139
49500
  exports.TableView = TableView;
49140
49501
  exports.TerrainPalette = TerrainPalette;
49141
49502
  exports.TimeSlotCell = TimeSlotCell;