@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.
@@ -3905,6 +3905,61 @@ var init_TextHighlight = __esm({
3905
3905
  }
3906
3906
  });
3907
3907
 
3908
+ // lib/format.ts
3909
+ function humanizeFieldName(name) {
3910
+ 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();
3911
+ }
3912
+ function humanizeEnumValue(value) {
3913
+ return /^[a-z0-9]+(?:[_-][a-z0-9]+)+$/.test(value) ? humanizeFieldName(value) : value;
3914
+ }
3915
+ function formatDate(value) {
3916
+ if (!value) return "";
3917
+ const d = new Date(String(value));
3918
+ if (isNaN(d.getTime())) return String(value);
3919
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
3920
+ }
3921
+ function formatTime(value) {
3922
+ if (!value) return "";
3923
+ const d = new Date(String(value));
3924
+ if (isNaN(d.getTime())) return String(value);
3925
+ return d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
3926
+ }
3927
+ function formatDateTime(value) {
3928
+ if (!value) return "";
3929
+ const d = new Date(String(value));
3930
+ if (isNaN(d.getTime())) return String(value);
3931
+ return `${formatDate(value)} ${formatTime(value)}`;
3932
+ }
3933
+ function asYesNo(value) {
3934
+ return value === false || value === 0 || String(value) === "false" ? "No" : "Yes";
3935
+ }
3936
+ function formatValue(value, format) {
3937
+ if (value === void 0 || value === null) return "";
3938
+ if (typeof value === "boolean") return asYesNo(value);
3939
+ switch (format) {
3940
+ case "date":
3941
+ return formatDate(value);
3942
+ case "time":
3943
+ return formatTime(value);
3944
+ case "datetime":
3945
+ return formatDateTime(value);
3946
+ case "currency":
3947
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
3948
+ case "number":
3949
+ return typeof value === "number" ? value.toLocaleString() : String(value);
3950
+ case "percent":
3951
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
3952
+ case "boolean":
3953
+ return asYesNo(value);
3954
+ default:
3955
+ return String(value);
3956
+ }
3957
+ }
3958
+ var init_format = __esm({
3959
+ "lib/format.ts"() {
3960
+ }
3961
+ });
3962
+
3908
3963
  // components/core/atoms/Typography.tsx
3909
3964
  var Typography_exports = {};
3910
3965
  __export(Typography_exports, {
@@ -3914,6 +3969,7 @@ var variantStyles6, colorStyles, weightStyles, defaultElements, typographySizeSt
3914
3969
  var init_Typography = __esm({
3915
3970
  "components/core/atoms/Typography.tsx"() {
3916
3971
  init_cn();
3972
+ init_format();
3917
3973
  variantStyles6 = {
3918
3974
  h1: "text-4xl font-bold tracking-tight text-foreground",
3919
3975
  h2: "text-3xl font-bold tracking-tight text-foreground",
@@ -4001,11 +4057,16 @@ var init_Typography = __esm({
4001
4057
  id,
4002
4058
  className,
4003
4059
  style,
4060
+ format,
4004
4061
  content,
4005
4062
  children
4006
4063
  }) => {
4007
4064
  const variant = variantProp ?? (level ? `h${level}` : "body1");
4008
4065
  const Component = as || defaultElements[variant];
4066
+ let body = children ?? content;
4067
+ if (format !== void 0 && format !== "none" && (typeof body === "string" || typeof body === "number" || body instanceof Date)) {
4068
+ body = formatValue(body, format);
4069
+ }
4009
4070
  return React74__default.createElement(
4010
4071
  Component,
4011
4072
  {
@@ -4022,7 +4083,7 @@ var init_Typography = __esm({
4022
4083
  ),
4023
4084
  style
4024
4085
  },
4025
- children ?? content
4086
+ body
4026
4087
  );
4027
4088
  };
4028
4089
  Typography.displayName = "Typography";
@@ -16597,9 +16658,6 @@ function normalizeFields(fields) {
16597
16658
  if (!fields) return [];
16598
16659
  return fields.map((f3) => typeof f3 === "string" ? f3 : f3.key ?? f3.name ?? "");
16599
16660
  }
16600
- function fieldLabel(key) {
16601
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
16602
- }
16603
16661
  function asBooleanValue(value) {
16604
16662
  if (typeof value === "boolean") return value;
16605
16663
  if (value === "true") return true;
@@ -16610,12 +16668,6 @@ function isDateField(key) {
16610
16668
  const lower = key.toLowerCase();
16611
16669
  return lower.includes("date") || lower.includes("time") || lower.endsWith("at") || lower.endsWith("_at");
16612
16670
  }
16613
- function formatDate(value) {
16614
- if (!value) return "";
16615
- const d = new Date(String(value));
16616
- if (isNaN(d.getTime())) return String(value);
16617
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
16618
- }
16619
16671
  function statusVariant(value) {
16620
16672
  const v = value.toLowerCase();
16621
16673
  if (["active", "completed", "done", "approved", "published", "resolved", "open"].includes(v)) return "success";
@@ -16624,11 +16676,12 @@ function statusVariant(value) {
16624
16676
  if (["new", "created", "scheduled", "queued"].includes(v)) return "info";
16625
16677
  return "default";
16626
16678
  }
16627
- var STATUS_FIELDS, gapStyles3, alignStyles2, CardGrid;
16679
+ var fieldLabel, STATUS_FIELDS, gapStyles3, alignStyles2, CardGrid;
16628
16680
  var init_CardGrid = __esm({
16629
16681
  "components/core/organisms/CardGrid.tsx"() {
16630
16682
  "use client";
16631
16683
  init_cn();
16684
+ init_format();
16632
16685
  init_getNestedValue();
16633
16686
  init_useEventBus();
16634
16687
  init_atoms();
@@ -16637,6 +16690,7 @@ var init_CardGrid = __esm({
16637
16690
  init_Typography();
16638
16691
  init_Stack();
16639
16692
  init_Pagination();
16693
+ fieldLabel = humanizeFieldName;
16640
16694
  STATUS_FIELDS = /* @__PURE__ */ new Set(["status", "state", "priority", "type", "category", "role", "level", "tier"]);
16641
16695
  gapStyles3 = {
16642
16696
  none: "gap-0",
@@ -17144,7 +17198,7 @@ var init_CaseStudyOrganism = __esm({
17144
17198
  CaseStudyOrganism.displayName = "CaseStudyOrganism";
17145
17199
  }
17146
17200
  });
17147
- var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, LOOK_FROM_CHART_TYPE, Chart;
17201
+ var CHART_COLORS, seriesColor, barColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, LOOK_FROM_CHART_TYPE, Chart;
17148
17202
  var init_Chart = __esm({
17149
17203
  "components/core/molecules/Chart.tsx"() {
17150
17204
  "use client";
@@ -17164,6 +17218,7 @@ var init_Chart = __esm({
17164
17218
  "var(--color-accent)"
17165
17219
  ];
17166
17220
  seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
17221
+ barColor = (series, sIdx, catIdx, seriesCount) => series.color ?? CHART_COLORS[(seriesCount === 1 ? catIdx : sIdx) % CHART_COLORS.length];
17167
17222
  monthFormatter = new Intl.DateTimeFormat(void 0, {
17168
17223
  month: "short",
17169
17224
  year: "2-digit"
@@ -17236,7 +17291,7 @@ var init_Chart = __esm({
17236
17291
  children: series.map((s, sIdx) => {
17237
17292
  const value = valueAt(s, label);
17238
17293
  const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
17239
- const color = seriesColor(s, sIdx);
17294
+ const color = barColor(s, sIdx, catIdx, series.length);
17240
17295
  return /* @__PURE__ */ jsx(
17241
17296
  Box,
17242
17297
  {
@@ -17291,7 +17346,7 @@ var init_Chart = __esm({
17291
17346
  /* @__PURE__ */ jsx(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) => {
17292
17347
  const value = valueAt(s, label);
17293
17348
  const barHeight = value / maxValue * 100;
17294
- const color = seriesColor(s, sIdx);
17349
+ const color = barColor(s, sIdx, catIdx, series.length);
17295
17350
  return /* @__PURE__ */ jsx(
17296
17351
  Box,
17297
17352
  {
@@ -17342,7 +17397,7 @@ var init_Chart = __esm({
17342
17397
  /* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full flex-1 min-h-0", justify: "end", children: series.map((s, sIdx) => {
17343
17398
  const value = valueAt(s, label);
17344
17399
  const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
17345
- const color = seriesColor(s, sIdx);
17400
+ const color = barColor(s, sIdx, catIdx, series.length);
17346
17401
  return /* @__PURE__ */ jsx(
17347
17402
  Box,
17348
17403
  {
@@ -20577,9 +20632,6 @@ var init_useDataDnd = __esm({
20577
20632
  function renderIconInput(icon, props) {
20578
20633
  return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
20579
20634
  }
20580
- function fieldLabel2(key) {
20581
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
20582
- }
20583
20635
  function statusVariant2(value) {
20584
20636
  const v = value.toLowerCase();
20585
20637
  if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
@@ -20598,29 +20650,6 @@ function resolveBadgeVariant(field, value) {
20598
20650
  }
20599
20651
  return statusVariant2(value);
20600
20652
  }
20601
- function formatDate2(value) {
20602
- if (!value) return "";
20603
- const d = new Date(String(value));
20604
- if (isNaN(d.getTime())) return String(value);
20605
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
20606
- }
20607
- function formatValue(value, format) {
20608
- if (value === void 0 || value === null) return "";
20609
- switch (format) {
20610
- case "date":
20611
- return formatDate2(value);
20612
- case "currency":
20613
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
20614
- case "number":
20615
- return typeof value === "number" ? value.toLocaleString() : String(value);
20616
- case "percent":
20617
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
20618
- case "boolean":
20619
- return value ? "Yes" : "No";
20620
- default:
20621
- return String(value);
20622
- }
20623
- }
20624
20653
  function DataGrid({
20625
20654
  entity,
20626
20655
  fields,
@@ -20907,7 +20936,7 @@ function DataGrid({
20907
20936
  if (val === void 0 || val === null || val === "") return null;
20908
20937
  return /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
20909
20938
  field.icon && renderIconInput(field.icon, { size: "xs" }),
20910
- /* @__PURE__ */ jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: formatValue(val, field.format) })
20939
+ /* @__PURE__ */ jsx(Badge, { variant: resolveBadgeVariant(field, String(val)), children: humanizeEnumValue(formatValue(val, field.format)) })
20911
20940
  ] }, field.name);
20912
20941
  }) })
20913
20942
  ] }),
@@ -21017,11 +21046,12 @@ function DataGrid({
21017
21046
  ] })
21018
21047
  );
21019
21048
  }
21020
- var dataGridLog, BADGE_VARIANTS, gapStyles5, lookStyles5;
21049
+ var dataGridLog, fieldLabel2, BADGE_VARIANTS, gapStyles5, lookStyles5;
21021
21050
  var init_DataGrid = __esm({
21022
21051
  "components/core/molecules/DataGrid.tsx"() {
21023
21052
  "use client";
21024
21053
  init_cn();
21054
+ init_format();
21025
21055
  init_getNestedValue();
21026
21056
  init_useEventBus();
21027
21057
  init_Box();
@@ -21034,6 +21064,7 @@ var init_DataGrid = __esm({
21034
21064
  init_Menu();
21035
21065
  init_useDataDnd();
21036
21066
  dataGridLog = createLogger("almadar:ui:data-grid");
21067
+ fieldLabel2 = humanizeFieldName;
21037
21068
  BADGE_VARIANTS = /* @__PURE__ */ new Set([
21038
21069
  "default",
21039
21070
  "primary",
@@ -21065,9 +21096,6 @@ var init_DataGrid = __esm({
21065
21096
  function renderIconInput2(icon, props) {
21066
21097
  return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
21067
21098
  }
21068
- function fieldLabel3(key) {
21069
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
21070
- }
21071
21099
  function statusVariant3(value) {
21072
21100
  const v = value.toLowerCase();
21073
21101
  if (["active", "completed", "done", "approved", "published", "resolved", "open", "online"].includes(v)) return "success";
@@ -21076,28 +21104,12 @@ function statusVariant3(value) {
21076
21104
  if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
21077
21105
  return "default";
21078
21106
  }
21079
- function formatDate3(value) {
21080
- if (!value) return "";
21081
- const d = new Date(String(value));
21082
- if (isNaN(d.getTime())) return String(value);
21083
- return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
21084
- }
21085
21107
  function formatValue2(value, format, boolLabels) {
21086
- if (value === void 0 || value === null) return "";
21087
- switch (format) {
21088
- case "date":
21089
- return formatDate3(value);
21090
- case "currency":
21091
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
21092
- case "number":
21093
- return typeof value === "number" ? value.toLocaleString() : String(value);
21094
- case "percent":
21095
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
21096
- case "boolean":
21097
- return value ? boolLabels?.yes ?? "Yes" : boolLabels?.no ?? "No";
21098
- default:
21099
- return String(value);
21108
+ if (value !== void 0 && value !== null && (format === "boolean" || typeof value === "boolean")) {
21109
+ const isNo = value === false || value === 0 || String(value) === "false";
21110
+ return isNo ? boolLabels?.no ?? "No" : boolLabels?.yes ?? "Yes";
21100
21111
  }
21112
+ return formatValue(value, format);
21101
21113
  }
21102
21114
  function groupData(items, field) {
21103
21115
  const groups = /* @__PURE__ */ new Map();
@@ -21120,7 +21132,9 @@ function DataList({
21120
21132
  variant = "default",
21121
21133
  groupBy,
21122
21134
  senderField,
21135
+ senderLabelField,
21123
21136
  currentUser,
21137
+ emptyMessage,
21124
21138
  className,
21125
21139
  isLoading = false,
21126
21140
  error = null,
@@ -21259,7 +21273,7 @@ function DataList({
21259
21273
  return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
21260
21274
  }
21261
21275
  if (data.length === 0) {
21262
- const emptyNode = /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") }) });
21276
+ const emptyNode = /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: emptyMessage || t("empty.noItems") }) });
21263
21277
  return dnd.enabled ? /* @__PURE__ */ jsx(Fragment, { children: dnd.wrapContainer(emptyNode) }) : emptyNode;
21264
21278
  }
21265
21279
  const gapClass = {
@@ -21275,51 +21289,93 @@ function DataList({
21275
21289
  const items2 = [...data];
21276
21290
  const groups2 = groupBy ? groupData(items2, groupBy) : [{ label: "", items: items2 }];
21277
21291
  const contentField = titleField?.name ?? fieldDefs[0]?.name ?? "";
21278
- return /* @__PURE__ */ jsx(VStack, { gap: "sm", className: cn("py-2", className), children: groups2.map((group, gi) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
21279
- group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
21280
- group.items.map((itemData, index) => {
21281
- const id = itemData.id || `${gi}-${index}`;
21282
- const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
21283
- const isSent = Boolean(currentUser && sender === currentUser);
21284
- const content = getNestedValue(itemData, contentField);
21285
- const timestampField = fieldDefs.find((f3) => f3.format === "date");
21286
- const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
21287
- return /* @__PURE__ */ jsx(
21288
- Box,
21289
- {
21290
- className: cn(
21291
- "flex px-4",
21292
- isSent ? "justify-end" : "justify-start"
21293
- ),
21294
- children: /* @__PURE__ */ jsxs(
21295
- Box,
21296
- {
21297
- className: cn(
21298
- "max-w-[75%] px-4 py-2",
21299
- isSent ? "bg-primary text-primary-foreground rounded-2xl rounded-br-sm" : "bg-muted text-foreground rounded-2xl rounded-bl-sm"
21300
- ),
21301
- children: [
21302
- !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: sender }),
21303
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
21304
- timestamp != null ? /* @__PURE__ */ jsx(
21305
- Typography,
21306
- {
21307
- variant: "caption",
21308
- className: cn(
21309
- "mt-1 text-xs",
21310
- isSent ? "opacity-70" : "text-muted-foreground"
21311
- ),
21312
- children: formatDate3(timestamp)
21313
- }
21314
- ) : null
21315
- ]
21316
- }
21317
- )
21318
- },
21319
- id
21320
- );
21321
- })
21322
- ] }, gi)) });
21292
+ const senderLabel = (itemData, raw) => {
21293
+ if (!senderLabelField) return raw;
21294
+ const v = getNestedValue(itemData, senderLabelField);
21295
+ return v === void 0 || v === null || v === "" ? raw : String(v);
21296
+ };
21297
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn("py-2", className), children: [
21298
+ groups2.map((group, gi) => /* @__PURE__ */ jsxs(React74__default.Fragment, { children: [
21299
+ group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: "my-2" }),
21300
+ group.items.map((itemData, index) => {
21301
+ const id = itemData.id || `${gi}-${index}`;
21302
+ const sender = senderField ? String(getNestedValue(itemData, senderField) ?? "") : "";
21303
+ const isSent = Boolean(currentUser && sender === currentUser);
21304
+ const content = getNestedValue(itemData, contentField);
21305
+ const timestampField = fieldDefs.find((f3) => f3.format === "date");
21306
+ const timestamp = timestampField ? getNestedValue(itemData, timestampField.name) : null;
21307
+ const metaFields = fieldDefs.filter(
21308
+ (f3) => f3.name !== contentField && f3.name !== timestampField?.name
21309
+ );
21310
+ return /* @__PURE__ */ jsx(
21311
+ Box,
21312
+ {
21313
+ "data-entity-row": true,
21314
+ "data-entity-id": id,
21315
+ onClick: itemClickEvent ? handleRowClick(itemData) : void 0,
21316
+ className: cn(
21317
+ "flex px-4 group/rowactions",
21318
+ itemClickEvent && "cursor-pointer",
21319
+ isSent ? "justify-end" : "justify-start"
21320
+ ),
21321
+ children: /* @__PURE__ */ jsxs(
21322
+ Box,
21323
+ {
21324
+ className: cn(
21325
+ "max-w-[75%] px-4 py-2",
21326
+ isSent ? "bg-primary text-primary-foreground rounded-2xl rounded-br-sm" : "bg-muted text-foreground rounded-2xl rounded-bl-sm"
21327
+ ),
21328
+ children: [
21329
+ !isSent && senderField && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "font-semibold mb-0.5", children: senderLabel(itemData, sender) }),
21330
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: cn(isSent && "text-primary-foreground"), children: content !== void 0 && content !== null ? String(content) : "" }),
21331
+ metaFields.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "mt-1 flex-wrap", children: metaFields.map((f3) => {
21332
+ const v = getNestedValue(itemData, f3.name);
21333
+ if (v === void 0 || v === null || v === "") return null;
21334
+ return f3.variant === "badge" ? /* @__PURE__ */ jsx(Badge, { variant: statusVariant3(String(v)), children: String(v) }, f3.name) : /* @__PURE__ */ jsx(
21335
+ Typography,
21336
+ {
21337
+ variant: "caption",
21338
+ className: cn("text-xs", isSent ? "opacity-70" : "text-muted-foreground"),
21339
+ children: formatValue2(v, f3.format)
21340
+ },
21341
+ f3.name
21342
+ );
21343
+ }) }),
21344
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "mt-1 items-center justify-between", children: [
21345
+ timestamp != null ? /* @__PURE__ */ jsx(
21346
+ Typography,
21347
+ {
21348
+ variant: "caption",
21349
+ className: cn("text-xs", isSent ? "opacity-70" : "text-muted-foreground"),
21350
+ children: formatDate(timestamp)
21351
+ }
21352
+ ) : /* @__PURE__ */ jsx("span", {}),
21353
+ renderItemActions(itemData)
21354
+ ] })
21355
+ ]
21356
+ }
21357
+ )
21358
+ },
21359
+ id
21360
+ );
21361
+ })
21362
+ ] }, gi)),
21363
+ hasMoreLocal && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(
21364
+ Button,
21365
+ {
21366
+ variant: "ghost",
21367
+ size: "sm",
21368
+ onClick: () => setVisibleCount((prev) => prev + (pageSize || 5)),
21369
+ children: [
21370
+ /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
21371
+ t("common.showMore"),
21372
+ " (",
21373
+ t("common.remaining", { count: allData.length - visibleCount }),
21374
+ ")"
21375
+ ]
21376
+ }
21377
+ ) })
21378
+ ] });
21323
21379
  }
21324
21380
  const items = [...data];
21325
21381
  const groups = groupBy ? groupData(items, groupBy) : [{ label: "", items }];
@@ -21468,11 +21524,12 @@ function DataList({
21468
21524
  )
21469
21525
  );
21470
21526
  }
21471
- var dataListLog, listLookStyles;
21527
+ var dataListLog, fieldLabel3, listLookStyles;
21472
21528
  var init_DataList = __esm({
21473
21529
  "components/core/molecules/DataList.tsx"() {
21474
21530
  "use client";
21475
21531
  init_cn();
21532
+ init_format();
21476
21533
  init_getNestedValue();
21477
21534
  init_useEventBus();
21478
21535
  init_Box();
@@ -21487,6 +21544,7 @@ var init_DataList = __esm({
21487
21544
  init_Menu();
21488
21545
  init_useDataDnd();
21489
21546
  dataListLog = createLogger("almadar:ui:data-list");
21547
+ fieldLabel3 = humanizeFieldName;
21490
21548
  listLookStyles = {
21491
21549
  dense: "[&_[data-entity-row]>div]:!py-1 [&_[data-entity-row]>div]:!px-3",
21492
21550
  spacious: "[&_[data-entity-row]>div]:!py-5 [&_[data-entity-row]>div]:!px-8",
@@ -25955,7 +26013,7 @@ var init_ScoreDisplay = __esm({
25955
26013
  ScoreDisplay.displayName = "ScoreDisplay";
25956
26014
  }
25957
26015
  });
25958
- function formatTime(seconds, format) {
26016
+ function formatTime2(seconds, format) {
25959
26017
  const clamped = Math.max(0, Math.floor(seconds));
25960
26018
  if (format === "ss") {
25961
26019
  return `${clamped}s`;
@@ -25992,7 +26050,7 @@ function TimerDisplay({
25992
26050
  ),
25993
26051
  children: [
25994
26052
  iconAsset && /* @__PURE__ */ jsx(GameIcon, { assetUrl: iconAsset, icon: "image", size: 16, className: "w-4 h-4 object-contain flex-shrink-0" }),
25995
- formatTime(seconds, format)
26053
+ formatTime2(seconds, format)
25996
26054
  ]
25997
26055
  }
25998
26056
  );
@@ -26060,6 +26118,210 @@ var init_DialogueBubble = __esm({
26060
26118
  DialogueBubble.displayName = "DialogueBubble";
26061
26119
  }
26062
26120
  });
26121
+ function SvgStage({
26122
+ cols,
26123
+ rows: rows2,
26124
+ tileSize = 32,
26125
+ background = "var(--color-background)",
26126
+ tileClickEvent,
26127
+ tileHoverEvent,
26128
+ tileLeaveEvent,
26129
+ keyMap,
26130
+ keyUpMap,
26131
+ className,
26132
+ children
26133
+ }) {
26134
+ const eventBus = useEventBus();
26135
+ const svgRef = useRef(null);
26136
+ const pointerDownRef = useRef(null);
26137
+ const cellFromClient = useCallback((clientX, clientY) => {
26138
+ const svg = svgRef.current;
26139
+ if (!svg) return null;
26140
+ const rect = svg.getBoundingClientRect();
26141
+ if (rect.width === 0 || rect.height === 0) return null;
26142
+ const vbW = cols * tileSize;
26143
+ const vbH = rows2 * tileSize;
26144
+ const meet = Math.min(rect.width / vbW, rect.height / vbH);
26145
+ const offsetX = (rect.width - vbW * meet) / 2;
26146
+ const offsetY = (rect.height - vbH * meet) / 2;
26147
+ const svgX = (clientX - rect.left - offsetX) / meet;
26148
+ const svgY = (clientY - rect.top - offsetY) / meet;
26149
+ return {
26150
+ x: Math.min(Math.max(Math.floor(svgX / tileSize), 0), cols - 1),
26151
+ y: Math.min(Math.max(Math.floor(svgY / tileSize), 0), rows2 - 1)
26152
+ };
26153
+ }, [cols, rows2, tileSize]);
26154
+ const handlePointerDown = useCallback((e) => {
26155
+ pointerDownRef.current = { clientX: e.clientX, clientY: e.clientY };
26156
+ }, []);
26157
+ const handlePointerUp = useCallback((e) => {
26158
+ const down = pointerDownRef.current;
26159
+ pointerDownRef.current = null;
26160
+ if (!tileClickEvent) return;
26161
+ if (down && Math.hypot(e.clientX - down.clientX, e.clientY - down.clientY) > 5) return;
26162
+ const cell = cellFromClient(e.clientX, e.clientY);
26163
+ if (cell) eventBus.emit(`UI:${tileClickEvent}`, cell);
26164
+ }, [cellFromClient, tileClickEvent, eventBus]);
26165
+ const handlePointerMove = useCallback((e) => {
26166
+ if (!tileHoverEvent) return;
26167
+ const cell = cellFromClient(e.clientX, e.clientY);
26168
+ if (cell) eventBus.emit(`UI:${tileHoverEvent}`, cell);
26169
+ }, [cellFromClient, tileHoverEvent, eventBus]);
26170
+ const handlePointerLeave = useCallback(() => {
26171
+ pointerDownRef.current = null;
26172
+ if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
26173
+ }, [tileLeaveEvent, eventBus]);
26174
+ useEffect(() => {
26175
+ if (!keyMap && !keyUpMap) return;
26176
+ const onDown = (e) => {
26177
+ const ev = keyMap?.[e.code];
26178
+ if (ev) {
26179
+ eventBus.emit(`UI:${ev}`, {});
26180
+ e.preventDefault();
26181
+ }
26182
+ };
26183
+ const onUp = (e) => {
26184
+ const ev = keyUpMap?.[e.code];
26185
+ if (ev) eventBus.emit(`UI:${ev}`, {});
26186
+ };
26187
+ window.addEventListener("keydown", onDown);
26188
+ window.addEventListener("keyup", onUp);
26189
+ return () => {
26190
+ window.removeEventListener("keydown", onDown);
26191
+ window.removeEventListener("keyup", onUp);
26192
+ };
26193
+ }, [keyMap, keyUpMap, eventBus]);
26194
+ useEffect(() => {
26195
+ if (!keyMap && !keyUpMap) return;
26196
+ svgRef.current?.focus();
26197
+ }, [keyMap, keyUpMap]);
26198
+ const stageContext = useMemo(() => ({ tileSize }), [tileSize]);
26199
+ return /* @__PURE__ */ jsxs(
26200
+ "svg",
26201
+ {
26202
+ ref: svgRef,
26203
+ "data-testid": "svg-stage",
26204
+ viewBox: `0 0 ${cols * tileSize} ${rows2 * tileSize}`,
26205
+ preserveAspectRatio: "xMidYMid meet",
26206
+ className: cn("block h-full w-full", className),
26207
+ tabIndex: keyMap || keyUpMap ? 0 : void 0,
26208
+ onPointerDown: handlePointerDown,
26209
+ onPointerMove: handlePointerMove,
26210
+ onPointerUp: handlePointerUp,
26211
+ onPointerLeave: handlePointerLeave,
26212
+ children: [
26213
+ /* @__PURE__ */ jsx("rect", { width: cols * tileSize, height: rows2 * tileSize, fill: background }),
26214
+ /* @__PURE__ */ jsx(SvgStageContext.Provider, { value: stageContext, children })
26215
+ ]
26216
+ }
26217
+ );
26218
+ }
26219
+ var SvgStageContext;
26220
+ var init_SvgStage = __esm({
26221
+ "components/game/molecules/SvgStage.tsx"() {
26222
+ "use client";
26223
+ init_cn();
26224
+ init_useEventBus();
26225
+ SvgStageContext = React74.createContext({ tileSize: 1 });
26226
+ SvgStage.displayName = "SvgStage";
26227
+ }
26228
+ });
26229
+ function SvgDrawShape({
26230
+ shape,
26231
+ x,
26232
+ y,
26233
+ width,
26234
+ height,
26235
+ radius,
26236
+ radiusY,
26237
+ points,
26238
+ d,
26239
+ x2,
26240
+ y2,
26241
+ fill,
26242
+ stroke,
26243
+ strokeWidth,
26244
+ opacity,
26245
+ className
26246
+ }) {
26247
+ const { tileSize } = useContext(SvgStageContext);
26248
+ const cell = (v) => v === void 0 ? void 0 : v * tileSize;
26249
+ const paint = {
26250
+ fill: fill ?? (stroke === void 0 ? "var(--color-primary)" : "none"),
26251
+ stroke,
26252
+ strokeWidth,
26253
+ opacity,
26254
+ className
26255
+ };
26256
+ return /* @__PURE__ */ jsxs("g", { transform: `translate(${x * tileSize} ${y * tileSize})`, children: [
26257
+ shape === "rect" && /* @__PURE__ */ jsx("rect", { width: cell(width), height: cell(height), ...paint }),
26258
+ shape === "circle" && /* @__PURE__ */ jsx("circle", { r: cell(radius), ...paint }),
26259
+ shape === "ellipse" && /* @__PURE__ */ jsx("ellipse", { rx: cell(radius), ry: cell(radiusY ?? radius), ...paint }),
26260
+ shape === "polygon" && /* @__PURE__ */ jsx("polygon", { points, ...paint }),
26261
+ shape === "polyline" && /* @__PURE__ */ jsx("polyline", { points, ...paint }),
26262
+ shape === "path" && /* @__PURE__ */ jsx("path", { d, ...paint }),
26263
+ shape === "line" && /* @__PURE__ */ jsx("line", { x2: cell(x2), y2: cell(y2), ...paint })
26264
+ ] });
26265
+ }
26266
+ var init_SvgDrawShape = __esm({
26267
+ "components/game/atoms/SvgDrawShape.tsx"() {
26268
+ "use client";
26269
+ init_SvgStage();
26270
+ SvgDrawShape.displayName = "SvgDrawShape";
26271
+ }
26272
+ });
26273
+ function SvgDrawGroup({
26274
+ x = 0,
26275
+ y = 0,
26276
+ scale,
26277
+ rotate,
26278
+ opacity,
26279
+ className,
26280
+ children
26281
+ }) {
26282
+ const { tileSize } = useContext(SvgStageContext);
26283
+ const transforms = [`translate(${x * tileSize} ${y * tileSize})`];
26284
+ if (rotate !== void 0) transforms.push(`rotate(${rotate})`);
26285
+ if (scale !== void 0) transforms.push(`scale(${scale})`);
26286
+ return /* @__PURE__ */ jsx("g", { transform: transforms.join(" "), opacity, className, children });
26287
+ }
26288
+ var init_SvgDrawGroup = __esm({
26289
+ "components/game/atoms/SvgDrawGroup.tsx"() {
26290
+ "use client";
26291
+ init_SvgStage();
26292
+ SvgDrawGroup.displayName = "SvgDrawGroup";
26293
+ }
26294
+ });
26295
+ function SvgDrawText({
26296
+ x,
26297
+ y,
26298
+ text,
26299
+ size = 12,
26300
+ fill = "var(--color-foreground)",
26301
+ anchor = "middle",
26302
+ className
26303
+ }) {
26304
+ const { tileSize } = useContext(SvgStageContext);
26305
+ return /* @__PURE__ */ jsx(
26306
+ "text",
26307
+ {
26308
+ x: x * tileSize,
26309
+ y: y * tileSize,
26310
+ fontSize: size,
26311
+ fill,
26312
+ textAnchor: anchor,
26313
+ className,
26314
+ children: text
26315
+ }
26316
+ );
26317
+ }
26318
+ var init_SvgDrawText = __esm({
26319
+ "components/game/atoms/SvgDrawText.tsx"() {
26320
+ "use client";
26321
+ init_SvgStage();
26322
+ SvgDrawText.displayName = "SvgDrawText";
26323
+ }
26324
+ });
26063
26325
  function StatBadge({
26064
26326
  assetUrl,
26065
26327
  iconUrl,
@@ -26550,6 +26812,32 @@ var init_StateGraph = __esm({
26550
26812
  init_TransitionArrow();
26551
26813
  }
26552
26814
  });
26815
+ function SvgDrawShapeLayer({
26816
+ items,
26817
+ fill,
26818
+ stroke,
26819
+ strokeWidth,
26820
+ opacity
26821
+ }) {
26822
+ return /* @__PURE__ */ jsx("g", { children: items.map(({ id, ...shape }) => /* @__PURE__ */ jsx(
26823
+ SvgDrawShape,
26824
+ {
26825
+ ...shape,
26826
+ fill: shape.fill ?? fill,
26827
+ stroke: shape.stroke ?? stroke,
26828
+ strokeWidth: shape.strokeWidth ?? strokeWidth,
26829
+ opacity: shape.opacity ?? opacity
26830
+ },
26831
+ id
26832
+ )) });
26833
+ }
26834
+ var init_SvgDrawShapeLayer = __esm({
26835
+ "components/game/molecules/SvgDrawShapeLayer.tsx"() {
26836
+ "use client";
26837
+ init_SvgDrawShape();
26838
+ SvgDrawShapeLayer.displayName = "SvgDrawShapeLayer";
26839
+ }
26840
+ });
26553
26841
  function unitAtlasUrl(unit) {
26554
26842
  return unit.spriteSheet?.url ?? null;
26555
26843
  }
@@ -28017,6 +28305,9 @@ var init_molecules = __esm({
28017
28305
  init_TimerDisplay();
28018
28306
  init_DialogueBubble();
28019
28307
  init_ChoiceButton();
28308
+ init_SvgDrawShape();
28309
+ init_SvgDrawGroup();
28310
+ init_SvgDrawText();
28020
28311
  init_ControlGrid();
28021
28312
  init_StatBadge();
28022
28313
  init_GameHud();
@@ -28024,6 +28315,8 @@ var init_molecules = __esm({
28024
28315
  init_StateGraph();
28025
28316
  init_Canvas2D();
28026
28317
  init_Canvas();
28318
+ init_SvgDrawShapeLayer();
28319
+ init_SvgStage();
28027
28320
  init_useUnitSpriteAtlas();
28028
28321
  init_GameAudioToggle();
28029
28322
  init_useGameAudio();
@@ -28641,13 +28934,13 @@ var init_MapView = __esm({
28641
28934
  shadowSize: [41, 41]
28642
28935
  });
28643
28936
  L.Marker.prototype.options.icon = defaultIcon;
28644
- const { useEffect: useEffect65, useRef: useRef63, useCallback: useCallback106, useState: useState102 } = React74__default;
28937
+ const { useEffect: useEffect66, useRef: useRef64, useCallback: useCallback107, useState: useState102 } = React74__default;
28645
28938
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
28646
28939
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
28647
28940
  function MapUpdater({ centerLat, centerLng, zoom }) {
28648
28941
  const map = useMap();
28649
- const prevRef = useRef63({ centerLat, centerLng, zoom });
28650
- useEffect65(() => {
28942
+ const prevRef = useRef64({ centerLat, centerLng, zoom });
28943
+ useEffect66(() => {
28651
28944
  const prev = prevRef.current;
28652
28945
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
28653
28946
  map.setView([centerLat, centerLng], zoom);
@@ -28658,7 +28951,7 @@ var init_MapView = __esm({
28658
28951
  }
28659
28952
  function MapClickHandler({ onMapClick }) {
28660
28953
  const map = useMap();
28661
- useEffect65(() => {
28954
+ useEffect66(() => {
28662
28955
  if (!onMapClick) return;
28663
28956
  const handler = (e) => {
28664
28957
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -28687,7 +28980,7 @@ var init_MapView = __esm({
28687
28980
  }) {
28688
28981
  const eventBus = useEventBus2();
28689
28982
  const [clickedPosition, setClickedPosition] = useState102(null);
28690
- const handleMapClick = useCallback106((lat, lng) => {
28983
+ const handleMapClick = useCallback107((lat, lng) => {
28691
28984
  if (showClickedPin) {
28692
28985
  setClickedPosition({ lat, lng });
28693
28986
  }
@@ -28696,7 +28989,7 @@ var init_MapView = __esm({
28696
28989
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
28697
28990
  }
28698
28991
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
28699
- const handleMarkerClick = useCallback106((marker) => {
28992
+ const handleMarkerClick = useCallback107((marker) => {
28700
28993
  onMarkerClick?.(marker);
28701
28994
  if (markerClickEvent) {
28702
28995
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -29496,7 +29789,7 @@ function renderIconInput3(icon, props) {
29496
29789
  return typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, ...props }) : /* @__PURE__ */ jsx(Icon, { icon, ...props });
29497
29790
  }
29498
29791
  function columnLabel(col) {
29499
- return col.header ?? col.label ?? col.key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
29792
+ return col.header ?? col.label ?? humanizeFieldName(col.key);
29500
29793
  }
29501
29794
  function asFieldValue(v) {
29502
29795
  if (v === void 0 || v === null) return v;
@@ -29515,25 +29808,6 @@ function statusVariant4(value) {
29515
29808
  if (["new", "created", "scheduled", "queued", "info"].includes(v)) return "info";
29516
29809
  return "default";
29517
29810
  }
29518
- function formatCell(value, format) {
29519
- if (value === void 0 || value === null) return "";
29520
- switch (format) {
29521
- case "date": {
29522
- const d = new Date(String(value));
29523
- return isNaN(d.getTime()) ? String(value) : d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
29524
- }
29525
- case "currency":
29526
- return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
29527
- case "number":
29528
- return typeof value === "number" ? value.toLocaleString() : String(value);
29529
- case "percent":
29530
- return typeof value === "number" ? `${Math.round(value)}%` : String(value);
29531
- case "boolean":
29532
- return value ? "Yes" : "No";
29533
- default:
29534
- return String(value);
29535
- }
29536
- }
29537
29811
  function groupData2(items, field) {
29538
29812
  const groups = /* @__PURE__ */ new Map();
29539
29813
  for (const item of items) {
@@ -29579,7 +29853,8 @@ function TableView({
29579
29853
  const { t } = useTranslate();
29580
29854
  const [visibleCount, setVisibleCount] = React74__default.useState(pageSize > 0 ? pageSize : Infinity);
29581
29855
  const [localSelected, setLocalSelected] = React74__default.useState(/* @__PURE__ */ new Set());
29582
- const colDefs = columns ?? fields ?? [];
29856
+ const colDefs = (Array.isArray(columns) ? columns : void 0) ?? (Array.isArray(fields) ? fields : void 0) ?? [];
29857
+ const actionDefs = Array.isArray(itemActions) ? itemActions : [];
29583
29858
  const allDataRaw = Array.isArray(entity) ? entity : entity ? [entity] : [];
29584
29859
  const dnd = useDataDnd({
29585
29860
  items: allDataRaw,
@@ -29599,6 +29874,23 @@ function TableView({
29599
29874
  const hasRenderProp = typeof children === "function";
29600
29875
  const idField = dndItemIdField ?? "id";
29601
29876
  const isCoarsePointer = useMediaQuery("(pointer: coarse)");
29877
+ React74__default.useEffect(() => {
29878
+ tableViewLog.debug("render", {
29879
+ rowCount: data.length,
29880
+ colCount: colDefs.length,
29881
+ look,
29882
+ isLoading: Boolean(isLoading),
29883
+ hasError: Boolean(error),
29884
+ dnd: dnd.enabled
29885
+ });
29886
+ if (data.length > 0 && !hasRenderProp && colDefs.length === 0) {
29887
+ tableViewLog.warn("columns-unresolved", {
29888
+ rowCount: data.length,
29889
+ columnsIsArray: Array.isArray(columns),
29890
+ fieldsIsArray: Array.isArray(fields)
29891
+ });
29892
+ }
29893
+ }, [data, colDefs, look, isLoading, error, dnd.enabled, hasRenderProp, columns, fields]);
29602
29894
  const selected = selectedIds ? new Set(selectedIds) : localSelected;
29603
29895
  const emitSelection = (next) => {
29604
29896
  if (!selectedIds) setLocalSelected(next);
@@ -29642,21 +29934,12 @@ function TableView({
29642
29934
  }),
29643
29935
  [colDefs, data]
29644
29936
  );
29645
- if (isLoading) {
29646
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) });
29647
- }
29648
- if (error) {
29649
- return /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
29650
- }
29651
- if (data.length === 0) {
29652
- const emptyNode = /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: emptyMessage || t("empty.noItems") }) });
29653
- return dnd.enabled ? /* @__PURE__ */ jsx(Fragment, { children: dnd.wrapContainer(emptyNode) }) : emptyNode;
29654
- }
29937
+ const statusNode = isLoading ? /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("loading.items") }) }) : error ? /* @__PURE__ */ jsx(Box, { className: "text-center py-8", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) }) : data.length === 0 ? /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: emptyMessage || t("empty.noItems") }) }) : null;
29655
29938
  const lk = LOOKS[look];
29656
- const hasActions = Boolean(itemActions && itemActions.length > 0);
29939
+ const hasActions = actionDefs.length > 0;
29657
29940
  const effectiveMaxInline = isCoarsePointer ? 0 : maxInlineActions;
29658
- const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(itemActions.length, effectiveMaxInline) : itemActions.length : 0;
29659
- const hasOverflowActions = hasActions && effectiveMaxInline != null && itemActions.length > effectiveMaxInline;
29941
+ const inlineActionCount = hasActions ? effectiveMaxInline != null ? Math.min(actionDefs.length, effectiveMaxInline) : actionDefs.length : 0;
29942
+ const hasOverflowActions = hasActions && effectiveMaxInline != null && actionDefs.length > effectiveMaxInline;
29660
29943
  const actionsTrack = hasActions ? `${inlineActionCount * 6 + (hasOverflowActions ? 3 : 0)}rem` : null;
29661
29944
  const gridTemplateColumns = [
29662
29945
  selectable ? "auto" : null,
@@ -29744,11 +30027,11 @@ function TableView({
29744
30027
  col.className
29745
30028
  );
29746
30029
  if (col.format === "badge" && raw != null && raw !== "") {
29747
- return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx(Badge, { variant: statusVariant4(String(raw)), size: "sm", className: "whitespace-nowrap", children: String(raw) }) }, col.key);
30030
+ return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx(Badge, { variant: statusVariant4(String(raw)), size: "sm", className: "whitespace-nowrap", children: humanizeEnumValue(String(raw)) }) }, col.key);
29748
30031
  }
29749
30032
  return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: formatCell(raw, col.format) }) }, col.key);
29750
30033
  }),
29751
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxs(
30034
+ hasActions && /* @__PURE__ */ jsxs(
29752
30035
  HStack,
29753
30036
  {
29754
30037
  gap: "xs",
@@ -29760,7 +30043,7 @@ function TableView({
29760
30043
  lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
29761
30044
  ),
29762
30045
  children: [
29763
- (effectiveMaxInline != null ? itemActions.slice(0, effectiveMaxInline) : itemActions).map((action, i) => /* @__PURE__ */ jsxs(
30046
+ (effectiveMaxInline != null ? actionDefs.slice(0, effectiveMaxInline) : actionDefs).map((action, i) => /* @__PURE__ */ jsxs(
29764
30047
  Button,
29765
30048
  {
29766
30049
  variant: action.variant === "primary" ? "primary" : "ghost",
@@ -29776,12 +30059,12 @@ function TableView({
29776
30059
  },
29777
30060
  i
29778
30061
  )),
29779
- effectiveMaxInline != null && itemActions.length > effectiveMaxInline && /* @__PURE__ */ jsx(
30062
+ effectiveMaxInline != null && actionDefs.length > effectiveMaxInline && /* @__PURE__ */ jsx(
29780
30063
  Menu,
29781
30064
  {
29782
30065
  position: "bottom-end",
29783
30066
  trigger: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
29784
- items: itemActions.slice(effectiveMaxInline).map((action) => ({
30067
+ items: actionDefs.slice(effectiveMaxInline).map((action) => ({
29785
30068
  label: action.label,
29786
30069
  icon: action.icon,
29787
30070
  event: action.event,
@@ -29808,15 +30091,16 @@ function TableView({
29808
30091
  group.label && /* @__PURE__ */ jsx(Divider, { label: group.label, className: gi > 0 ? "mt-3" : "mt-0" }),
29809
30092
  group.items.map((row) => renderRow(row, runningIndex++))
29810
30093
  ] }, gi)) });
30094
+ const showHeader = colDefs.length > 0 || hasRenderProp;
29811
30095
  return /* @__PURE__ */ jsxs(
29812
30096
  Box,
29813
30097
  {
29814
30098
  role: "table",
29815
30099
  className: cn("w-full text-sm", className),
29816
30100
  children: [
29817
- header,
29818
- dnd.wrapContainer(body),
29819
- hasMore && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setVisibleCount((p) => p + (pageSize || 5)), children: [
30101
+ showHeader && header,
30102
+ dnd.wrapContainer(statusNode ? /* @__PURE__ */ jsx(Box, { role: "rowgroup", children: statusNode }) : body),
30103
+ !statusNode && hasMore && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setVisibleCount((p) => p + (pageSize || 5)), children: [
29820
30104
  /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
29821
30105
  t("common.showMore"),
29822
30106
  " (",
@@ -29827,11 +30111,12 @@ function TableView({
29827
30111
  }
29828
30112
  );
29829
30113
  }
29830
- var MAX_MEASURED_COL_CH, BADGE_CHROME_CH, alignClass, weightClass, LOOKS;
30114
+ var tableViewLog, formatCell, MAX_MEASURED_COL_CH, BADGE_CHROME_CH, alignClass, weightClass, LOOKS;
29831
30115
  var init_TableView = __esm({
29832
30116
  "components/core/molecules/TableView.tsx"() {
29833
30117
  "use client";
29834
30118
  init_cn();
30119
+ init_format();
29835
30120
  init_getNestedValue();
29836
30121
  init_useEventBus();
29837
30122
  init_useMediaQuery();
@@ -29845,7 +30130,8 @@ var init_TableView = __esm({
29845
30130
  init_Divider();
29846
30131
  init_Menu();
29847
30132
  init_useDataDnd();
29848
- createLogger("almadar:ui:table-view");
30133
+ tableViewLog = createLogger("almadar:ui:table-view");
30134
+ formatCell = (value, format) => formatValue(value, format);
29849
30135
  MAX_MEASURED_COL_CH = 32;
29850
30136
  BADGE_CHROME_CH = 4;
29851
30137
  alignClass = {
@@ -37229,6 +37515,7 @@ var init_GraphCanvas = __esm({
37229
37515
  title,
37230
37516
  nodes: propNodes = NO_NODES,
37231
37517
  edges: propEdges = NO_EDGES,
37518
+ proposedEdges = NO_EDGES,
37232
37519
  similarity: propSimilarity = NO_SIM,
37233
37520
  height = 400,
37234
37521
  showLabels = true,
@@ -37236,6 +37523,7 @@ var init_GraphCanvas = __esm({
37236
37523
  draggable = true,
37237
37524
  actions,
37238
37525
  onNodeClick,
37526
+ onMarkClick,
37239
37527
  onNodeDoubleClick,
37240
37528
  onBadgeClick,
37241
37529
  nodeClickEvent,
@@ -37264,6 +37552,18 @@ var init_GraphCanvas = __esm({
37264
37552
  const laidOutRef = useRef(false);
37265
37553
  const [, forceUpdate] = useState(0);
37266
37554
  const [logicalW, setLogicalW] = useState(800);
37555
+ const hasProposed = useMemo(() => propNodes.some((n) => n.mark?.kind === "proposed"), [propNodes]);
37556
+ const [pulseTick, setPulseTick] = useState(0);
37557
+ useEffect(() => {
37558
+ if (!hasProposed) return;
37559
+ let raf = 0;
37560
+ const loop = () => {
37561
+ setPulseTick((t2) => (t2 + 1) % 1e6);
37562
+ raf = requestAnimationFrame(loop);
37563
+ };
37564
+ raf = requestAnimationFrame(loop);
37565
+ return () => cancelAnimationFrame(raf);
37566
+ }, [hasProposed]);
37267
37567
  useEffect(() => {
37268
37568
  const canvas = canvasRef.current;
37269
37569
  if (!canvas || typeof ResizeObserver === "undefined") return;
@@ -37565,18 +37865,38 @@ var init_GraphCanvas = __esm({
37565
37865
  }
37566
37866
  }
37567
37867
  ctx.globalAlpha = 1;
37868
+ ctx.setLineDash([4, 4]);
37869
+ for (const edge of proposedEdges) {
37870
+ const source = nodes.find((n) => n.id === edge.source);
37871
+ const target = nodes.find((n) => n.id === edge.target);
37872
+ if (!source || !target) continue;
37873
+ ctx.globalAlpha = 0.4;
37874
+ ctx.beginPath();
37875
+ ctx.moveTo(source.x, source.y);
37876
+ ctx.lineTo(target.x, target.y);
37877
+ ctx.strokeStyle = edge.color || mutedColor;
37878
+ ctx.lineWidth = 1;
37879
+ ctx.stroke();
37880
+ }
37881
+ ctx.setLineDash([]);
37882
+ ctx.globalAlpha = 1;
37568
37883
  for (const node of nodes) {
37569
37884
  const size = node.size || 8;
37570
37885
  const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
37571
37886
  const isHovered = hoveredNode === node.id;
37572
37887
  const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
37573
- ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
37888
+ const mark = node.mark;
37889
+ ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : mark?.kind === "proposed" ? 0.55 : 1;
37574
37890
  const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
37575
37891
  ctx.beginPath();
37576
37892
  ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
37577
- ctx.fillStyle = color;
37893
+ ctx.fillStyle = mark?.kind === "proposed" ? mutedColor : color;
37578
37894
  ctx.fill();
37579
- if (isSelected) {
37895
+ if (mark?.kind === "proposed") {
37896
+ ctx.setLineDash([3, 3]);
37897
+ ctx.strokeStyle = resolveColor3(mark.tint ?? "var(--color-warning)", canvas);
37898
+ ctx.lineWidth = 1.5;
37899
+ } else if (isSelected) {
37580
37900
  ctx.strokeStyle = accentColor;
37581
37901
  ctx.lineWidth = 3;
37582
37902
  } else {
@@ -37584,6 +37904,28 @@ var init_GraphCanvas = __esm({
37584
37904
  ctx.lineWidth = isHovered ? 2 : 1;
37585
37905
  }
37586
37906
  ctx.stroke();
37907
+ ctx.setLineDash([]);
37908
+ if (mark?.kind === "suggested") {
37909
+ ctx.beginPath();
37910
+ ctx.arc(node.x, node.y, radius + 3, 0, Math.PI * 2);
37911
+ ctx.strokeStyle = accentColor;
37912
+ ctx.lineWidth = 2;
37913
+ ctx.stroke();
37914
+ ctx.beginPath();
37915
+ ctx.arc(node.x + radius * 0.7, node.y - radius * 0.7, 2.5, 0, Math.PI * 2);
37916
+ ctx.fillStyle = accentColor;
37917
+ ctx.fill();
37918
+ } else if (mark?.kind === "proposed") {
37919
+ const phase = pulseTick % 60 / 60;
37920
+ const baseAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 0.55;
37921
+ ctx.globalAlpha = baseAlpha * (0.4 + 0.4 * (1 - Math.abs(phase * 2 - 1)));
37922
+ ctx.beginPath();
37923
+ ctx.arc(node.x, node.y, radius + 6 + Math.sin(phase * Math.PI * 2) * 3, 0, Math.PI * 2);
37924
+ ctx.strokeStyle = resolveColor3(mark.tint ?? "var(--color-warning)", canvas);
37925
+ ctx.lineWidth = 1.5;
37926
+ ctx.stroke();
37927
+ ctx.globalAlpha = baseAlpha;
37928
+ }
37587
37929
  if (showLabels && node.label) {
37588
37930
  const displayLabel = truncateLabel(node.label);
37589
37931
  ctx.font = `${isSelected || isHovered ? "700" : "600"} 12px ${fontFamily}`;
@@ -37718,11 +38060,15 @@ var init_GraphCanvas = __esm({
37718
38060
  return;
37719
38061
  }
37720
38062
  }
38063
+ if (node.mark && onMarkClick) {
38064
+ onMarkClick(node);
38065
+ return;
38066
+ }
37721
38067
  handleNodeClick(node);
37722
38068
  }
37723
38069
  }
37724
38070
  },
37725
- [toCoords, nodeAt, handleNodeClick, onBadgeClick, selectedNodeId]
38071
+ [toCoords, nodeAt, handleNodeClick, onBadgeClick, onMarkClick, selectedNodeId]
37726
38072
  );
37727
38073
  const handlePointerLeave = useCallback(() => {
37728
38074
  setHoveredNode(null);
@@ -38470,9 +38816,6 @@ var init_types2 = __esm({
38470
38816
  };
38471
38817
  }
38472
38818
  });
38473
- function humanizeFieldName(name) {
38474
- 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();
38475
- }
38476
38819
  function normalizeColumns(columns) {
38477
38820
  return columns.map((col) => {
38478
38821
  if (typeof col === "string") {
@@ -38897,6 +39240,7 @@ var init_DataTable = __esm({
38897
39240
  "components/core/organisms/DataTable.tsx"() {
38898
39241
  "use client";
38899
39242
  init_cn();
39243
+ init_format();
38900
39244
  init_getNestedValue();
38901
39245
  init_atoms();
38902
39246
  init_Box();
@@ -38949,9 +39293,6 @@ function getBadgeVariant(fieldName, value) {
38949
39293
  }
38950
39294
  return "default";
38951
39295
  }
38952
- function formatFieldLabel(fieldName) {
38953
- return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
38954
- }
38955
39296
  function formatFieldValue2(value, fieldName) {
38956
39297
  if (typeof value === "number") {
38957
39298
  if (fieldName.toLowerCase().includes("progress") || fieldName.toLowerCase().includes("percent")) {
@@ -39079,7 +39420,7 @@ function buildFieldTypeMap(fields) {
39079
39420
  }
39080
39421
  return map;
39081
39422
  }
39082
- var ReactMarkdown2, DetailPanel;
39423
+ var formatFieldLabel, ReactMarkdown2, DetailPanel;
39083
39424
  var init_DetailPanel = __esm({
39084
39425
  "components/core/organisms/DetailPanel.tsx"() {
39085
39426
  "use client";
@@ -39091,8 +39432,10 @@ var init_DetailPanel = __esm({
39091
39432
  init_ErrorState();
39092
39433
  init_EmptyState();
39093
39434
  init_cn();
39435
+ init_format();
39094
39436
  init_getNestedValue();
39095
39437
  init_useEventBus();
39438
+ formatFieldLabel = humanizeFieldName;
39096
39439
  ReactMarkdown2 = lazy(() => import('react-markdown'));
39097
39440
  DetailPanel = ({
39098
39441
  title: propTitle,
@@ -40621,7 +40964,7 @@ function formatValue3(value, fieldName) {
40621
40964
  return String(value);
40622
40965
  }
40623
40966
  function formatFieldLabel2(fieldName) {
40624
- return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
40967
+ return humanizeFieldName(fieldName).replace(/\sId$/, "").trim();
40625
40968
  }
40626
40969
  var STATUS_STYLES, StatusBadge, ProgressIndicator, List3;
40627
40970
  var init_List = __esm({
@@ -40633,6 +40976,7 @@ var init_List = __esm({
40633
40976
  init_EmptyState();
40634
40977
  init_LoadingState();
40635
40978
  init_cn();
40979
+ init_format();
40636
40980
  init_getNestedValue();
40637
40981
  init_useEventBus();
40638
40982
  init_types2();
@@ -42094,7 +42438,7 @@ function TicksTab({ ticks: ticks2 }) {
42094
42438
  }
42095
42439
  );
42096
42440
  }
42097
- const formatTime2 = (ms) => {
42441
+ const formatTime3 = (ms) => {
42098
42442
  if (ms === 0) return "never";
42099
42443
  const seconds = Math.floor((Date.now() - ms) / 1e3);
42100
42444
  if (seconds < 1) return "just now";
@@ -42120,7 +42464,7 @@ function TicksTab({ ticks: ticks2 }) {
42120
42464
  tick.executionTime.toFixed(1),
42121
42465
  "ms exec"
42122
42466
  ] }),
42123
- /* @__PURE__ */ jsx("span", { children: formatTime2(tick.lastRun) })
42467
+ /* @__PURE__ */ jsx("span", { children: formatTime3(tick.lastRun) })
42124
42468
  ] }),
42125
42469
  tick.guardName && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxs(Badge, { variant: tick.guardPassed ? "success" : "danger", size: "sm", children: [
42126
42470
  tick.guardName,
@@ -42244,7 +42588,7 @@ function EventFlowTab({ events: events2 }) {
42244
42588
  if (filter === "all") return events2;
42245
42589
  return events2.filter((e) => e.type === filter);
42246
42590
  }, [events2, filter]);
42247
- const formatTime2 = (timestamp) => {
42591
+ const formatTime3 = (timestamp) => {
42248
42592
  const date = new Date(timestamp);
42249
42593
  return date.toLocaleTimeString("en-US", {
42250
42594
  hour12: false,
@@ -42320,7 +42664,7 @@ function EventFlowTab({ events: events2 }) {
42320
42664
  {
42321
42665
  className: "flex items-start gap-2 text-xs py-1 hover:bg-muted/50 rounded px-1",
42322
42666
  children: [
42323
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime2(event.timestamp) }),
42667
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime3(event.timestamp) }),
42324
42668
  /* @__PURE__ */ jsx("span", { children: icon }),
42325
42669
  /* @__PURE__ */ jsx(Badge, { variant, size: "sm", className: "min-w-[60px] justify-center", children: event.source }),
42326
42670
  /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground", children: event.message })
@@ -42374,7 +42718,7 @@ function GuardsPanel({ guards }) {
42374
42718
  if (filter === "passed") return guards.filter((g) => g.result);
42375
42719
  return guards.filter((g) => !g.result);
42376
42720
  }, [guards, filter]);
42377
- const formatTime2 = (timestamp) => {
42721
+ const formatTime3 = (timestamp) => {
42378
42722
  const date = new Date(timestamp);
42379
42723
  return date.toLocaleTimeString("en-US", {
42380
42724
  hour12: false,
@@ -42389,7 +42733,7 @@ function GuardsPanel({ guards }) {
42389
42733
  /* @__PURE__ */ jsx(Badge, { variant: guard.result ? "success" : "danger", size: "sm", children: guard.result ? "\u2713" : "\u2717" }),
42390
42734
  /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "semibold", className: "text-warning", children: guard.guardName }),
42391
42735
  /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground", children: guard.context.type === "transition" ? `${guard.context.transitionFrom} \u2192 ${guard.context.transitionTo}` : guard.context.tickName }),
42392
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground ml-auto", children: formatTime2(guard.timestamp) })
42736
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground ml-auto", children: formatTime3(guard.timestamp) })
42393
42737
  ] }),
42394
42738
  content: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
42395
42739
  /* @__PURE__ */ jsxs("div", { children: [
@@ -42550,7 +42894,7 @@ function TransitionTimeline({ transitions }) {
42550
42894
  }
42551
42895
  );
42552
42896
  }
42553
- const formatTime2 = (ts) => {
42897
+ const formatTime3 = (ts) => {
42554
42898
  const d = new Date(ts);
42555
42899
  return d.toLocaleTimeString("en-US", {
42556
42900
  hour12: false,
@@ -42598,7 +42942,7 @@ function TransitionTimeline({ transitions }) {
42598
42942
  ${hasFailedEffects ? "bg-error" : allPassed ? "bg-success" : "bg-muted-foreground"}
42599
42943
  ` }),
42600
42944
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs py-1 px-2", children: [
42601
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime2(trace.timestamp) }),
42945
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground font-mono min-w-[65px]", children: formatTime3(trace.timestamp) }),
42602
42946
  /* @__PURE__ */ jsx(Badge, { variant: "primary", size: "sm", className: "min-w-[60px] justify-center", children: trace.traitName }),
42603
42947
  /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-muted-foreground", children: [
42604
42948
  trace.from,
@@ -42673,7 +43017,7 @@ function ServerBridgeTab({ bridge }) {
42673
43017
  }
42674
43018
  );
42675
43019
  }
42676
- const formatTime2 = (ts) => {
43020
+ const formatTime3 = (ts) => {
42677
43021
  if (ts === 0) return t("debug.never");
42678
43022
  const d = new Date(ts);
42679
43023
  return d.toLocaleTimeString("en-US", {
@@ -42716,7 +43060,7 @@ function ServerBridgeTab({ bridge }) {
42716
43060
  StatRow,
42717
43061
  {
42718
43062
  label: t("debug.lastHeartbeat"),
42719
- value: formatTime2(bridge.lastHeartbeat)
43063
+ value: formatTime3(bridge.lastHeartbeat)
42720
43064
  }
42721
43065
  )
42722
43066
  ] })
@@ -44828,7 +45172,7 @@ var init_TeamOrganism = __esm({
44828
45172
  TeamOrganism.displayName = "TeamOrganism";
44829
45173
  }
44830
45174
  });
44831
- function formatDate4(value) {
45175
+ function formatDate2(value) {
44832
45176
  const d = new Date(value);
44833
45177
  if (isNaN(d.getTime())) return value;
44834
45178
  return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
@@ -44960,7 +45304,7 @@ var init_Timeline = __esm({
44960
45304
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: cn("flex-1 min-w-0", !isLast && "pb-6"), children: [
44961
45305
  /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "start", wrap: true, children: [
44962
45306
  /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "semibold", children: item.title }),
44963
- item.date && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: formatDate4(item.date) })
45307
+ item.date && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "flex-shrink-0", children: formatDate2(item.date) })
44964
45308
  ] }),
44965
45309
  item.description && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: item.description }),
44966
45310
  item.tags && item.tags.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: item.tags.map((tag, tagIdx) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: tag }, tagIdx)) }),
@@ -45266,6 +45610,10 @@ var init_component_registry_generated = __esm({
45266
45610
  init_SubagentTracePanel();
45267
45611
  init_SvgBranch();
45268
45612
  init_SvgConnection();
45613
+ init_SvgDrawGroup();
45614
+ init_SvgDrawShape();
45615
+ init_SvgDrawShapeLayer();
45616
+ init_SvgDrawText();
45269
45617
  init_SvgFlow();
45270
45618
  init_SvgGrid();
45271
45619
  init_SvgLobe();
@@ -45276,6 +45624,7 @@ var init_component_registry_generated = __esm({
45276
45624
  init_SvgRing();
45277
45625
  init_SvgShield();
45278
45626
  init_SvgStack();
45627
+ init_SvgStage();
45279
45628
  init_SwipeableRow();
45280
45629
  init_Switch();
45281
45630
  init_TabbedContainer();
@@ -45537,6 +45886,10 @@ var init_component_registry_generated = __esm({
45537
45886
  "SubagentTracePanel": SubagentTracePanel,
45538
45887
  "SvgBranch": SvgBranch,
45539
45888
  "SvgConnection": SvgConnection,
45889
+ "SvgDrawGroup": SvgDrawGroup,
45890
+ "SvgDrawShape": SvgDrawShape,
45891
+ "SvgDrawShapeLayer": SvgDrawShapeLayer,
45892
+ "SvgDrawText": SvgDrawText,
45540
45893
  "SvgFlow": SvgFlow,
45541
45894
  "SvgGrid": SvgGrid,
45542
45895
  "SvgLobe": SvgLobe,
@@ -45547,6 +45900,7 @@ var init_component_registry_generated = __esm({
45547
45900
  "SvgRing": SvgRing,
45548
45901
  "SvgShield": SvgShield,
45549
45902
  "SvgStack": SvgStack,
45903
+ "SvgStage": SvgStage,
45550
45904
  "SwipeableRow": SwipeableRow,
45551
45905
  "Switch": Switch,
45552
45906
  "TabbedContainer": TabbedContainer,
@@ -45623,7 +45977,7 @@ function enrichFormFields(fields, entityDef) {
45623
45977
  if (entityField) {
45624
45978
  const enriched = {
45625
45979
  name: field,
45626
- label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()),
45980
+ label: humanizeFieldName(field),
45627
45981
  type: entityField.type,
45628
45982
  required: entityField.required ?? false
45629
45983
  };
@@ -45637,7 +45991,7 @@ function enrichFormFields(fields, entityDef) {
45637
45991
  }
45638
45992
  return enriched;
45639
45993
  }
45640
- return { name: field, label: field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()) };
45994
+ return { name: field, label: humanizeFieldName(field) };
45641
45995
  }
45642
45996
  if (field && typeof field === "object" && !Array.isArray(field) && !React74__default.isValidElement(field) && !(field instanceof Date)) {
45643
45997
  const obj = field;
@@ -46292,9 +46646,10 @@ function SlotContentRenderer({
46292
46646
  const slotVal = restProps[slotKey];
46293
46647
  if (slotVal === void 0 || slotVal === null) continue;
46294
46648
  if (React74__default.isValidElement(slotVal) || typeof slotVal === "string" || typeof slotVal === "number" || typeof slotVal === "boolean") continue;
46295
- if (Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
46649
+ const typelessChildren = !Array.isArray(slotVal) && typeof slotVal === "object" && !("type" in slotVal) && Array.isArray(slotVal.children) ? slotVal.children : void 0;
46650
+ if (typelessChildren !== void 0 || Array.isArray(slotVal) || typeof slotVal === "object" && "type" in slotVal) {
46296
46651
  nodeSlotOverrides[slotKey] = renderPatternChildren(
46297
- slotVal,
46652
+ typelessChildren ?? slotVal,
46298
46653
  onDismiss,
46299
46654
  `${content.id}-${slotKey}`,
46300
46655
  `${myPath}.${slotKey}`,
@@ -46473,6 +46828,7 @@ var init_UISlotRenderer = __esm({
46473
46828
  init_useEventBus();
46474
46829
  init_slot_types();
46475
46830
  init_cn();
46831
+ init_format();
46476
46832
  init_ErrorBoundary();
46477
46833
  init_Skeleton();
46478
46834
  init_renderer();
@@ -49000,4 +49356,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
49000
49356
  });
49001
49357
  }
49002
49358
 
49003
- export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AlgorithmCanvas, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AtlasImage, AtlasPanel, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioToggle, GameHud, GameIcon, GameMenu, GameShell, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, ImportPreviewTree, ImportProgress, ImportSourcePicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, Modal, ModalSlot, ModuleCard, Navigation, NodeSlotEditor, NotifyListener, NumberStepper, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, PageTransition, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, Presence, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, RichBlockEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, ServiceCatalog, SharedEntityStoreContext, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateGraph, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VersionDiff, ViolationAlert, VoteStack, WizardContainer, WizardNavigation, WizardProgress, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createInitialGameState, createSharedEntityStore, createTranslate, createUnitAnimationState, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, registerCodeLanguageLoader, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, runTickFrame, screenToIso, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, useAgentChat, useAnchorRect, useAtlasSliceDataUrl, useAuthContext, useCamera, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useMediaQuery, useOrbitalHistory, usePresence, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useSwipeGesture, useTapReveal, useTraitListens, useTranslate114 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };
49359
+ export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AlgorithmCanvas, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AtlasImage, AtlasPanel, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioToggle, GameHud, GameIcon, GameMenu, GameShell, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, ImportPreviewTree, ImportProgress, ImportSourcePicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, Modal, ModalSlot, ModuleCard, Navigation, NodeSlotEditor, NotifyListener, NumberStepper, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, PageTransition, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, Presence, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, RichBlockEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, ServiceCatalog, SharedEntityStoreContext, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateGraph, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgDrawGroup, SvgDrawShape, SvgDrawShapeLayer, SvgDrawText, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SvgStage, SvgStageContext, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VersionDiff, ViolationAlert, VoteStack, WizardContainer, WizardNavigation, WizardProgress, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createInitialGameState, createSharedEntityStore, createTranslate, createUnitAnimationState, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, registerCodeLanguageLoader, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, runTickFrame, screenToIso, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, useAgentChat, useAnchorRect, useAtlasSliceDataUrl, useAuthContext, useCamera, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useMediaQuery, useOrbitalHistory, usePresence, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSharedEntitySnapshot, useSharedEntityStore, useSharedEntityStoreContext, useSwipeGesture, useTapReveal, useTraitListens, useTranslate114 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };