@almadar/ui 5.124.0 → 5.125.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.
@@ -20895,13 +20895,13 @@ function DataGrid({
20895
20895
  }
20896
20896
  ),
20897
20897
  /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
20898
- titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", className: "items-center", children: [
20898
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", className: "items-center min-w-0", children: [
20899
20899
  titleField?.icon && renderIconInput(titleField.icon, { size: "sm", className: "text-primary flex-shrink-0" }),
20900
20900
  /* @__PURE__ */ jsxRuntime.jsx(
20901
20901
  exports.Typography,
20902
20902
  {
20903
20903
  variant: titleField?.variant === "h3" ? "h3" : "h4",
20904
- className: "font-semibold truncate",
20904
+ className: "font-semibold truncate min-w-0",
20905
20905
  children: String(titleValue)
20906
20906
  }
20907
20907
  )
@@ -20959,7 +20959,7 @@ function DataGrid({
20959
20959
  )
20960
20960
  ] }, field.name);
20961
20961
  }) }) }),
20962
- primaryActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "justify-end", children: [
20962
+ primaryActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "justify-end flex-wrap", children: [
20963
20963
  (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
20964
20964
  exports.Button,
20965
20965
  {
@@ -29626,7 +29626,7 @@ function TableView({
29626
29626
  col.key
29627
29627
  );
29628
29628
  }),
29629
- hasActions && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { "aria-hidden": true })
29629
+ hasActions && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { "aria-hidden": true, className: "sticky right-0 bg-[var(--color-surface-subtle)]" })
29630
29630
  ]
29631
29631
  }
29632
29632
  );
@@ -29670,41 +29670,54 @@ function TableView({
29670
29670
  }
29671
29671
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
29672
29672
  }),
29673
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", className: "justify-end flex-shrink-0 opacity-60 group-hover:opacity-100 transition-opacity", children: [
29674
- (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
29675
- exports.Button,
29676
- {
29677
- variant: action.variant ?? "ghost",
29678
- size: "sm",
29679
- onClick: handleActionClick(action, row),
29680
- "data-testid": `action-${action.event}`,
29681
- "data-row-id": String(row.id),
29682
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
29683
- children: [
29684
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
29685
- action.label
29686
- ]
29687
- },
29688
- i
29689
- )),
29690
- maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
29691
- exports.Menu,
29692
- {
29693
- position: "bottom-end",
29694
- 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" }) }),
29695
- items: itemActions.slice(maxInlineActions).map((action) => ({
29696
- label: action.label,
29697
- icon: action.icon,
29698
- event: action.event,
29699
- variant: action.variant === "danger" ? "danger" : "default",
29700
- onClick: () => eventBus.emit(`UI:${action.event}`, {
29701
- id: row.id,
29702
- row
29703
- })
29704
- }))
29705
- }
29706
- )
29707
- ] })
29673
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
29674
+ exports.HStack,
29675
+ {
29676
+ gap: "xs",
29677
+ className: cn(
29678
+ // Pinned: the fixed column tracks routinely overflow the caller's
29679
+ // scroll container, which used to leave the actions off-screen.
29680
+ // Opaque so scrolled cells pass underneath it.
29681
+ "justify-end flex-shrink-0 sticky right-0 z-[1] transition-colors",
29682
+ lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
29683
+ ),
29684
+ children: [
29685
+ (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
29686
+ exports.Button,
29687
+ {
29688
+ variant: action.variant ?? "ghost",
29689
+ size: "sm",
29690
+ onClick: handleActionClick(action, row),
29691
+ "data-testid": `action-${action.event}`,
29692
+ "data-row-id": String(row.id),
29693
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
29694
+ children: [
29695
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
29696
+ action.label
29697
+ ]
29698
+ },
29699
+ i
29700
+ )),
29701
+ maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
29702
+ exports.Menu,
29703
+ {
29704
+ position: "bottom-end",
29705
+ 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" }) }),
29706
+ items: itemActions.slice(maxInlineActions).map((action) => ({
29707
+ label: action.label,
29708
+ icon: action.icon,
29709
+ event: action.event,
29710
+ variant: action.variant === "danger" ? "danger" : "default",
29711
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
29712
+ id: row.id,
29713
+ row
29714
+ })
29715
+ }))
29716
+ }
29717
+ )
29718
+ ]
29719
+ }
29720
+ )
29708
29721
  ]
29709
29722
  }
29710
29723
  );
@@ -38657,6 +38670,16 @@ function normalizeFieldDefs(fields) {
38657
38670
  return String(f3);
38658
38671
  });
38659
38672
  }
38673
+ function buildFieldLabelMap(fields) {
38674
+ const map = {};
38675
+ if (!fields) return map;
38676
+ for (const f3 of fields) {
38677
+ if (typeof f3 === "object" && "key" in f3 && f3.header !== void 0 && f3.header !== "") {
38678
+ map[f3.key] = f3.header;
38679
+ }
38680
+ }
38681
+ return map;
38682
+ }
38660
38683
  function buildFieldTypeMap(fields) {
38661
38684
  const map = {};
38662
38685
  if (!fields) return map;
@@ -38708,6 +38731,8 @@ var init_DetailPanel = __esm({
38708
38731
  };
38709
38732
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
38710
38733
  const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
38734
+ const fieldLabelMap = isFieldDefArray(propFields) ? buildFieldLabelMap(propFields) : {};
38735
+ const labelFor = (field) => fieldLabelMap[field] ?? formatFieldLabel(field);
38711
38736
  const handleActionClick = React74.useCallback(
38712
38737
  (action, data2) => {
38713
38738
  if (action.navigatesTo) {
@@ -38743,7 +38768,7 @@ var init_DetailPanel = __esm({
38743
38768
  if (typeof field === "string") {
38744
38769
  const value = getNestedValue(normalizedData, field);
38745
38770
  return {
38746
- label: formatFieldLabel(field),
38771
+ label: labelFor(field),
38747
38772
  value: formatFieldValue(value, field),
38748
38773
  icon: getFieldIcon(field)
38749
38774
  };
@@ -38754,7 +38779,10 @@ var init_DetailPanel = __esm({
38754
38779
  }
38755
38780
  if (normalizedData && effectiveFieldNames) {
38756
38781
  const primaryField = effectiveFieldNames[0];
38757
- if (!title && primaryField && normalizedData[primaryField]) {
38782
+ const titleDerivedFromPrimary = Boolean(
38783
+ !title && primaryField && normalizedData[primaryField]
38784
+ );
38785
+ if (titleDerivedFromPrimary) {
38758
38786
  title = String(normalizedData[primaryField]);
38759
38787
  }
38760
38788
  const statusFields = effectiveFieldNames.filter(
@@ -38773,16 +38801,16 @@ var init_DetailPanel = __esm({
38773
38801
  (f3) => f3.toLowerCase().includes("description") || f3.toLowerCase().includes("note")
38774
38802
  );
38775
38803
  const otherFields = effectiveFieldNames.filter(
38776
- (f3) => f3 !== primaryField && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
38804
+ (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
38777
38805
  );
38778
38806
  sections = [];
38779
38807
  if (statusFields.length > 0 || otherFields.length > 0) {
38780
38808
  const overviewFields = [];
38781
- [...statusFields, ...otherFields.slice(0, 3)].forEach((field) => {
38809
+ [...statusFields, ...otherFields].forEach((field) => {
38782
38810
  const value = getNestedValue(normalizedData, field);
38783
38811
  if (value !== void 0 && value !== null) {
38784
38812
  overviewFields.push({
38785
- label: formatFieldLabel(field),
38813
+ label: labelFor(field),
38786
38814
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38787
38815
  icon: getFieldIcon(field)
38788
38816
  });
@@ -38798,7 +38826,7 @@ var init_DetailPanel = __esm({
38798
38826
  const value = getNestedValue(normalizedData, field);
38799
38827
  if (value !== void 0 && value !== null) {
38800
38828
  metricsFields.push({
38801
- label: formatFieldLabel(field),
38829
+ label: labelFor(field),
38802
38830
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38803
38831
  icon: getFieldIcon(field)
38804
38832
  });
@@ -38814,7 +38842,7 @@ var init_DetailPanel = __esm({
38814
38842
  const value = getNestedValue(normalizedData, field);
38815
38843
  if (value !== void 0 && value !== null) {
38816
38844
  timelineFields.push({
38817
- label: formatFieldLabel(field),
38845
+ label: labelFor(field),
38818
38846
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38819
38847
  icon: getFieldIcon(field)
38820
38848
  });
@@ -38830,7 +38858,7 @@ var init_DetailPanel = __esm({
38830
38858
  const value = getNestedValue(normalizedData, field);
38831
38859
  if (value !== void 0 && value !== null) {
38832
38860
  descFields.push({
38833
- label: formatFieldLabel(field),
38861
+ label: labelFor(field),
38834
38862
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38835
38863
  icon: getFieldIcon(field)
38836
38864
  });
@@ -38878,7 +38906,7 @@ var init_DetailPanel = __esm({
38878
38906
  if (typeof field === "string") {
38879
38907
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
38880
38908
  allFields.push({
38881
- label: formatFieldLabel(field),
38909
+ label: labelFor(field),
38882
38910
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38883
38911
  icon: getFieldIcon(field)
38884
38912
  });
@@ -20820,13 +20820,13 @@ function DataGrid({
20820
20820
  }
20821
20821
  ),
20822
20822
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
20823
- titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center", children: [
20823
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center min-w-0", children: [
20824
20824
  titleField?.icon && renderIconInput(titleField.icon, { size: "sm", className: "text-primary flex-shrink-0" }),
20825
20825
  /* @__PURE__ */ jsx(
20826
20826
  Typography,
20827
20827
  {
20828
20828
  variant: titleField?.variant === "h3" ? "h3" : "h4",
20829
- className: "font-semibold truncate",
20829
+ className: "font-semibold truncate min-w-0",
20830
20830
  children: String(titleValue)
20831
20831
  }
20832
20832
  )
@@ -20884,7 +20884,7 @@ function DataGrid({
20884
20884
  )
20885
20885
  ] }, field.name);
20886
20886
  }) }) }),
20887
- primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-end", children: [
20887
+ primaryActions.length > 0 && /* @__PURE__ */ jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "justify-end flex-wrap", children: [
20888
20888
  (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxs(
20889
20889
  Button,
20890
20890
  {
@@ -29551,7 +29551,7 @@ function TableView({
29551
29551
  col.key
29552
29552
  );
29553
29553
  }),
29554
- hasActions && /* @__PURE__ */ jsx(Box, { "aria-hidden": true })
29554
+ hasActions && /* @__PURE__ */ jsx(Box, { "aria-hidden": true, className: "sticky right-0 bg-[var(--color-surface-subtle)]" })
29555
29555
  ]
29556
29556
  }
29557
29557
  );
@@ -29595,41 +29595,54 @@ function TableView({
29595
29595
  }
29596
29596
  return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
29597
29597
  }),
29598
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "justify-end flex-shrink-0 opacity-60 group-hover:opacity-100 transition-opacity", children: [
29599
- (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxs(
29600
- Button,
29601
- {
29602
- variant: action.variant ?? "ghost",
29603
- size: "sm",
29604
- onClick: handleActionClick(action, row),
29605
- "data-testid": `action-${action.event}`,
29606
- "data-row-id": String(row.id),
29607
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
29608
- children: [
29609
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
29610
- action.label
29611
- ]
29612
- },
29613
- i
29614
- )),
29615
- maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsx(
29616
- Menu,
29617
- {
29618
- position: "bottom-end",
29619
- 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" }) }),
29620
- items: itemActions.slice(maxInlineActions).map((action) => ({
29621
- label: action.label,
29622
- icon: action.icon,
29623
- event: action.event,
29624
- variant: action.variant === "danger" ? "danger" : "default",
29625
- onClick: () => eventBus.emit(`UI:${action.event}`, {
29626
- id: row.id,
29627
- row
29628
- })
29629
- }))
29630
- }
29631
- )
29632
- ] })
29598
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxs(
29599
+ HStack,
29600
+ {
29601
+ gap: "xs",
29602
+ className: cn(
29603
+ // Pinned: the fixed column tracks routinely overflow the caller's
29604
+ // scroll container, which used to leave the actions off-screen.
29605
+ // Opaque so scrolled cells pass underneath it.
29606
+ "justify-end flex-shrink-0 sticky right-0 z-[1] transition-colors",
29607
+ lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
29608
+ ),
29609
+ children: [
29610
+ (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxs(
29611
+ Button,
29612
+ {
29613
+ variant: action.variant ?? "ghost",
29614
+ size: "sm",
29615
+ onClick: handleActionClick(action, row),
29616
+ "data-testid": `action-${action.event}`,
29617
+ "data-row-id": String(row.id),
29618
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
29619
+ children: [
29620
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
29621
+ action.label
29622
+ ]
29623
+ },
29624
+ i
29625
+ )),
29626
+ maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsx(
29627
+ Menu,
29628
+ {
29629
+ position: "bottom-end",
29630
+ 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" }) }),
29631
+ items: itemActions.slice(maxInlineActions).map((action) => ({
29632
+ label: action.label,
29633
+ icon: action.icon,
29634
+ event: action.event,
29635
+ variant: action.variant === "danger" ? "danger" : "default",
29636
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
29637
+ id: row.id,
29638
+ row
29639
+ })
29640
+ }))
29641
+ }
29642
+ )
29643
+ ]
29644
+ }
29645
+ )
29633
29646
  ]
29634
29647
  }
29635
29648
  );
@@ -38582,6 +38595,16 @@ function normalizeFieldDefs(fields) {
38582
38595
  return String(f3);
38583
38596
  });
38584
38597
  }
38598
+ function buildFieldLabelMap(fields) {
38599
+ const map = {};
38600
+ if (!fields) return map;
38601
+ for (const f3 of fields) {
38602
+ if (typeof f3 === "object" && "key" in f3 && f3.header !== void 0 && f3.header !== "") {
38603
+ map[f3.key] = f3.header;
38604
+ }
38605
+ }
38606
+ return map;
38607
+ }
38585
38608
  function buildFieldTypeMap(fields) {
38586
38609
  const map = {};
38587
38610
  if (!fields) return map;
@@ -38633,6 +38656,8 @@ var init_DetailPanel = __esm({
38633
38656
  };
38634
38657
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
38635
38658
  const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
38659
+ const fieldLabelMap = isFieldDefArray(propFields) ? buildFieldLabelMap(propFields) : {};
38660
+ const labelFor = (field) => fieldLabelMap[field] ?? formatFieldLabel(field);
38636
38661
  const handleActionClick = useCallback(
38637
38662
  (action, data2) => {
38638
38663
  if (action.navigatesTo) {
@@ -38668,7 +38693,7 @@ var init_DetailPanel = __esm({
38668
38693
  if (typeof field === "string") {
38669
38694
  const value = getNestedValue(normalizedData, field);
38670
38695
  return {
38671
- label: formatFieldLabel(field),
38696
+ label: labelFor(field),
38672
38697
  value: formatFieldValue(value, field),
38673
38698
  icon: getFieldIcon(field)
38674
38699
  };
@@ -38679,7 +38704,10 @@ var init_DetailPanel = __esm({
38679
38704
  }
38680
38705
  if (normalizedData && effectiveFieldNames) {
38681
38706
  const primaryField = effectiveFieldNames[0];
38682
- if (!title && primaryField && normalizedData[primaryField]) {
38707
+ const titleDerivedFromPrimary = Boolean(
38708
+ !title && primaryField && normalizedData[primaryField]
38709
+ );
38710
+ if (titleDerivedFromPrimary) {
38683
38711
  title = String(normalizedData[primaryField]);
38684
38712
  }
38685
38713
  const statusFields = effectiveFieldNames.filter(
@@ -38698,16 +38726,16 @@ var init_DetailPanel = __esm({
38698
38726
  (f3) => f3.toLowerCase().includes("description") || f3.toLowerCase().includes("note")
38699
38727
  );
38700
38728
  const otherFields = effectiveFieldNames.filter(
38701
- (f3) => f3 !== primaryField && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
38729
+ (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
38702
38730
  );
38703
38731
  sections = [];
38704
38732
  if (statusFields.length > 0 || otherFields.length > 0) {
38705
38733
  const overviewFields = [];
38706
- [...statusFields, ...otherFields.slice(0, 3)].forEach((field) => {
38734
+ [...statusFields, ...otherFields].forEach((field) => {
38707
38735
  const value = getNestedValue(normalizedData, field);
38708
38736
  if (value !== void 0 && value !== null) {
38709
38737
  overviewFields.push({
38710
- label: formatFieldLabel(field),
38738
+ label: labelFor(field),
38711
38739
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38712
38740
  icon: getFieldIcon(field)
38713
38741
  });
@@ -38723,7 +38751,7 @@ var init_DetailPanel = __esm({
38723
38751
  const value = getNestedValue(normalizedData, field);
38724
38752
  if (value !== void 0 && value !== null) {
38725
38753
  metricsFields.push({
38726
- label: formatFieldLabel(field),
38754
+ label: labelFor(field),
38727
38755
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38728
38756
  icon: getFieldIcon(field)
38729
38757
  });
@@ -38739,7 +38767,7 @@ var init_DetailPanel = __esm({
38739
38767
  const value = getNestedValue(normalizedData, field);
38740
38768
  if (value !== void 0 && value !== null) {
38741
38769
  timelineFields.push({
38742
- label: formatFieldLabel(field),
38770
+ label: labelFor(field),
38743
38771
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38744
38772
  icon: getFieldIcon(field)
38745
38773
  });
@@ -38755,7 +38783,7 @@ var init_DetailPanel = __esm({
38755
38783
  const value = getNestedValue(normalizedData, field);
38756
38784
  if (value !== void 0 && value !== null) {
38757
38785
  descFields.push({
38758
- label: formatFieldLabel(field),
38786
+ label: labelFor(field),
38759
38787
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38760
38788
  icon: getFieldIcon(field)
38761
38789
  });
@@ -38803,7 +38831,7 @@ var init_DetailPanel = __esm({
38803
38831
  if (typeof field === "string") {
38804
38832
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
38805
38833
  allFields.push({
38806
- label: formatFieldLabel(field),
38834
+ label: labelFor(field),
38807
38835
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38808
38836
  icon: getFieldIcon(field)
38809
38837
  });
@@ -40,6 +40,24 @@ declare function extractRouteParams(pattern: string, path: string): Record<strin
40
40
  * Check if a path matches a pattern.
41
41
  */
42
42
  declare function pathMatches(pattern: string, path: string): boolean;
43
+ /**
44
+ * Order two route patterns most-specific-first: at the first segment where they
45
+ * disagree in kind, a static segment outranks a `:param`. Patterns that agree in
46
+ * kind everywhere tie, leaving declaration order to decide.
47
+ *
48
+ * Without this, `/listings/:id` declared before `/listings/moderation` swallows
49
+ * its static sibling, because every `:param` matches any segment.
50
+ */
51
+ declare function comparePathSpecificity(a: string, b: string): number;
52
+ /**
53
+ * Match a concrete path against route-bearing candidates, most-specific first.
54
+ * The single resolver every route lookup goes through — the candidate array is
55
+ * never reordered in place, so callers keep their declaration-order semantics.
56
+ */
57
+ declare function matchPathAmong<T>(candidates: readonly T[], path: string, pathOf: (candidate: T) => string | undefined): {
58
+ candidate: T;
59
+ params: Record<string, string>;
60
+ } | null;
43
61
  /**
44
62
  * Find a page in the schema by matching its path pattern against a concrete path.
45
63
  * Returns the page and extracted route params.
@@ -517,4 +535,4 @@ interface UseOfflineExecutorResult {
517
535
  */
518
536
  declare function useOfflineExecutor(options: UseOfflineExecutorOptions): UseOfflineExecutorResult;
519
537
 
520
- export { type ClientEffect as C, type DataContext as D, type EventResponse as E, type MappedPattern as M, type NavigationContextValue as N, OfflineExecutor as O, type PendingSyncEffect as P, type SlotDefinition as S, type UseOfflineExecutorResult as U, type UseOfflineExecutorOptions as a, NavigationProvider as b, type NavigationProviderProps as c, type NavigationState as d, extractRouteParams as e, findPageByName as f, findPageByPath as g, getAllPages as h, getDefaultPage as i, useInitPayload as j, useNavigateTo as k, useNavigation as l, matchPath as m, useNavigationId as n, useNavigationState as o, pathMatches as p, type ClientEffectExecutorConfig as q, type NotifyOptions as r, type DataResolution as s, type OfflineExecutorConfig as t, useActivePage as u, type OfflineExecutorState as v, type SlotType as w, createOfflineExecutor as x, useOfflineExecutor as y };
538
+ export { useOfflineExecutor as A, type ClientEffect as C, type DataContext as D, type EventResponse as E, type MappedPattern as M, type NavigationContextValue as N, OfflineExecutor as O, type PendingSyncEffect as P, type SlotDefinition as S, type UseOfflineExecutorResult as U, type UseOfflineExecutorOptions as a, NavigationProvider as b, type NavigationProviderProps as c, type NavigationState as d, comparePathSpecificity as e, extractRouteParams as f, findPageByName as g, findPageByPath as h, getAllPages as i, getDefaultPage as j, matchPathAmong as k, useInitPayload as l, matchPath as m, useNavigateTo as n, useNavigation as o, pathMatches as p, useNavigationId as q, useNavigationState as r, type ClientEffectExecutorConfig as s, type NotifyOptions as t, useActivePage as u, type DataResolution as v, type OfflineExecutorConfig as w, type OfflineExecutorState as x, type SlotType as y, createOfflineExecutor as z };
@@ -40,6 +40,24 @@ declare function extractRouteParams(pattern: string, path: string): Record<strin
40
40
  * Check if a path matches a pattern.
41
41
  */
42
42
  declare function pathMatches(pattern: string, path: string): boolean;
43
+ /**
44
+ * Order two route patterns most-specific-first: at the first segment where they
45
+ * disagree in kind, a static segment outranks a `:param`. Patterns that agree in
46
+ * kind everywhere tie, leaving declaration order to decide.
47
+ *
48
+ * Without this, `/listings/:id` declared before `/listings/moderation` swallows
49
+ * its static sibling, because every `:param` matches any segment.
50
+ */
51
+ declare function comparePathSpecificity(a: string, b: string): number;
52
+ /**
53
+ * Match a concrete path against route-bearing candidates, most-specific first.
54
+ * The single resolver every route lookup goes through — the candidate array is
55
+ * never reordered in place, so callers keep their declaration-order semantics.
56
+ */
57
+ declare function matchPathAmong<T>(candidates: readonly T[], path: string, pathOf: (candidate: T) => string | undefined): {
58
+ candidate: T;
59
+ params: Record<string, string>;
60
+ } | null;
43
61
  /**
44
62
  * Find a page in the schema by matching its path pattern against a concrete path.
45
63
  * Returns the page and extracted route params.
@@ -517,4 +535,4 @@ interface UseOfflineExecutorResult {
517
535
  */
518
536
  declare function useOfflineExecutor(options: UseOfflineExecutorOptions): UseOfflineExecutorResult;
519
537
 
520
- export { type ClientEffect as C, type DataContext as D, type EventResponse as E, type MappedPattern as M, type NavigationContextValue as N, OfflineExecutor as O, type PendingSyncEffect as P, type SlotDefinition as S, type UseOfflineExecutorResult as U, type UseOfflineExecutorOptions as a, NavigationProvider as b, type NavigationProviderProps as c, type NavigationState as d, extractRouteParams as e, findPageByName as f, findPageByPath as g, getAllPages as h, getDefaultPage as i, useInitPayload as j, useNavigateTo as k, useNavigation as l, matchPath as m, useNavigationId as n, useNavigationState as o, pathMatches as p, type ClientEffectExecutorConfig as q, type NotifyOptions as r, type DataResolution as s, type OfflineExecutorConfig as t, useActivePage as u, type OfflineExecutorState as v, type SlotType as w, createOfflineExecutor as x, useOfflineExecutor as y };
538
+ export { useOfflineExecutor as A, type ClientEffect as C, type DataContext as D, type EventResponse as E, type MappedPattern as M, type NavigationContextValue as N, OfflineExecutor as O, type PendingSyncEffect as P, type SlotDefinition as S, type UseOfflineExecutorResult as U, type UseOfflineExecutorOptions as a, NavigationProvider as b, type NavigationProviderProps as c, type NavigationState as d, comparePathSpecificity as e, extractRouteParams as f, findPageByName as g, findPageByPath as h, getAllPages as i, getDefaultPage as j, matchPathAmong as k, useInitPayload as l, matchPath as m, useNavigateTo as n, useNavigation as o, pathMatches as p, useNavigationId as q, useNavigationState as r, type ClientEffectExecutorConfig as s, type NotifyOptions as t, useActivePage as u, type DataResolution as v, type OfflineExecutorConfig as w, type OfflineExecutorState as x, type SlotType as y, createOfflineExecutor as z };