@almadar/ui 5.124.0 → 5.126.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.
@@ -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 };
@@ -18989,17 +18989,27 @@ function getWeekDays(start) {
18989
18989
  }
18990
18990
  return days;
18991
18991
  }
18992
- function generateDefaultTimeSlots() {
18992
+ function generateDefaultTimeSlots(events2) {
18993
+ let first = DEFAULT_FIRST_HOUR;
18994
+ let last = DEFAULT_LAST_HOUR;
18995
+ for (const ev of events2) {
18996
+ const start = new Date(ev.startTime);
18997
+ if (Number.isNaN(start.getTime())) continue;
18998
+ const hour = start.getHours();
18999
+ if (hour < first) first = hour;
19000
+ if (hour > last) last = hour;
19001
+ }
18993
19002
  const slots = [];
18994
- for (let hour = 9; hour <= 17; hour++) {
18995
- slots.push(`${hour.toString().padStart(2, "0")}:00`);
19003
+ for (let hour = first; hour <= last; hour++) {
19004
+ slots.push(slotLabel(hour));
18996
19005
  }
18997
19006
  return slots;
18998
19007
  }
18999
19008
  function eventInSlot(event, day, slotTime) {
19000
19009
  const eventStart = new Date(event.startTime);
19001
- const [slotHour, slotMinute] = slotTime.split(":").map(Number);
19002
- return eventStart.toDateString() === day.toDateString() && eventStart.getHours() === slotHour && eventStart.getMinutes() === slotMinute;
19010
+ if (Number.isNaN(eventStart.getTime())) return false;
19011
+ const [slotHour] = slotTime.split(":").map(Number);
19012
+ return eventStart.toDateString() === day.toDateString() && eventStart.getHours() === slotHour;
19003
19013
  }
19004
19014
  function CalendarGrid({
19005
19015
  weekStart,
@@ -19028,8 +19038,8 @@ function CalendarGrid({
19028
19038
  [resolvedWeekStart]
19029
19039
  );
19030
19040
  const resolvedTimeSlots = React84.useMemo(
19031
- () => timeSlots ?? generateDefaultTimeSlots(),
19032
- [timeSlots]
19041
+ () => timeSlots ?? generateDefaultTimeSlots(evs),
19042
+ [timeSlots, evs]
19033
19043
  );
19034
19044
  const visibleCount = useDayWindow(dayWindow);
19035
19045
  const [dayOffset, setDayOffset] = React84.useState(0);
@@ -19216,7 +19226,7 @@ function CalendarGrid({
19216
19226
  }
19217
19227
  );
19218
19228
  }
19219
- var SHORT_DATE;
19229
+ var SHORT_DATE, DEFAULT_FIRST_HOUR, DEFAULT_LAST_HOUR, slotLabel;
19220
19230
  var init_CalendarGrid = __esm({
19221
19231
  "components/core/molecules/CalendarGrid.tsx"() {
19222
19232
  "use client";
@@ -19231,6 +19241,9 @@ var init_CalendarGrid = __esm({
19231
19241
  init_useEventBus();
19232
19242
  init_useSwipeGesture();
19233
19243
  SHORT_DATE = { month: "short", day: "numeric" };
19244
+ DEFAULT_FIRST_HOUR = 9;
19245
+ DEFAULT_LAST_HOUR = 17;
19246
+ slotLabel = (hour) => `${hour.toString().padStart(2, "0")}:00`;
19234
19247
  CalendarGrid.displayName = "CalendarGrid";
19235
19248
  }
19236
19249
  });
@@ -23315,13 +23328,13 @@ function DataGrid({
23315
23328
  }
23316
23329
  ),
23317
23330
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "flex-1 min-w-0", children: [
23318
- titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center", children: [
23331
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "items-center min-w-0", children: [
23319
23332
  titleField?.icon && renderIconInput(titleField.icon, { size: "sm", className: "text-primary flex-shrink-0" }),
23320
23333
  /* @__PURE__ */ jsxRuntime.jsx(
23321
23334
  Typography,
23322
23335
  {
23323
23336
  variant: titleField?.variant === "h3" ? "h3" : "h4",
23324
- className: "font-semibold truncate",
23337
+ className: "font-semibold truncate min-w-0",
23325
23338
  children: String(titleValue)
23326
23339
  }
23327
23340
  )
@@ -23379,7 +23392,7 @@ function DataGrid({
23379
23392
  )
23380
23393
  ] }, field.name);
23381
23394
  }) }) }),
23382
- primaryActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-end", children: [
23395
+ primaryActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-3 mt-auto border-t border-border", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "justify-end flex-wrap", children: [
23383
23396
  (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
23384
23397
  Button,
23385
23398
  {
@@ -28392,7 +28405,7 @@ function TableView({
28392
28405
  col.key
28393
28406
  );
28394
28407
  }),
28395
- hasActions && /* @__PURE__ */ jsxRuntime.jsx(Box, { "aria-hidden": true })
28408
+ hasActions && /* @__PURE__ */ jsxRuntime.jsx(Box, { "aria-hidden": true, className: "sticky right-0 bg-[var(--color-surface-subtle)]" })
28396
28409
  ]
28397
28410
  }
28398
28411
  );
@@ -28436,41 +28449,54 @@ function TableView({
28436
28449
  }
28437
28450
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
28438
28451
  }),
28439
- itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", className: "justify-end flex-shrink-0 opacity-60 group-hover:opacity-100 transition-opacity", children: [
28440
- (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28441
- Button,
28442
- {
28443
- variant: action.variant ?? "ghost",
28444
- size: "sm",
28445
- onClick: handleActionClick(action, row),
28446
- "data-testid": `action-${action.event}`,
28447
- "data-row-id": String(row.id),
28448
- className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
28449
- children: [
28450
- action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
28451
- action.label
28452
- ]
28453
- },
28454
- i
28455
- )),
28456
- maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
28457
- Menu,
28458
- {
28459
- position: "bottom-end",
28460
- trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
28461
- items: itemActions.slice(maxInlineActions).map((action) => ({
28462
- label: action.label,
28463
- icon: action.icon,
28464
- event: action.event,
28465
- variant: action.variant === "danger" ? "danger" : "default",
28466
- onClick: () => eventBus.emit(`UI:${action.event}`, {
28467
- id: row.id,
28468
- row
28469
- })
28470
- }))
28471
- }
28472
- )
28473
- ] })
28452
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
28453
+ HStack,
28454
+ {
28455
+ gap: "xs",
28456
+ className: cn(
28457
+ // Pinned: the fixed column tracks routinely overflow the caller's
28458
+ // scroll container, which used to leave the actions off-screen.
28459
+ // Opaque so scrolled cells pass underneath it.
28460
+ "justify-end flex-shrink-0 sticky right-0 z-[1] transition-colors",
28461
+ lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
28462
+ ),
28463
+ children: [
28464
+ (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxRuntime.jsxs(
28465
+ Button,
28466
+ {
28467
+ variant: action.variant ?? "ghost",
28468
+ size: "sm",
28469
+ onClick: handleActionClick(action, row),
28470
+ "data-testid": `action-${action.event}`,
28471
+ "data-row-id": String(row.id),
28472
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
28473
+ children: [
28474
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
28475
+ action.label
28476
+ ]
28477
+ },
28478
+ i
28479
+ )),
28480
+ maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsxRuntime.jsx(
28481
+ Menu,
28482
+ {
28483
+ position: "bottom-end",
28484
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("common.actions"), "data-testid": "action-overflow", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "more-horizontal", size: "xs" }) }),
28485
+ items: itemActions.slice(maxInlineActions).map((action) => ({
28486
+ label: action.label,
28487
+ icon: action.icon,
28488
+ event: action.event,
28489
+ variant: action.variant === "danger" ? "danger" : "default",
28490
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
28491
+ id: row.id,
28492
+ row
28493
+ })
28494
+ }))
28495
+ }
28496
+ )
28497
+ ]
28498
+ }
28499
+ )
28474
28500
  ]
28475
28501
  }
28476
28502
  );
@@ -37205,6 +37231,16 @@ function normalizeFieldDefs(fields) {
37205
37231
  return String(f3);
37206
37232
  });
37207
37233
  }
37234
+ function buildFieldLabelMap(fields) {
37235
+ const map = {};
37236
+ if (!fields) return map;
37237
+ for (const f3 of fields) {
37238
+ if (typeof f3 === "object" && "key" in f3 && f3.header !== void 0 && f3.header !== "") {
37239
+ map[f3.key] = f3.header;
37240
+ }
37241
+ }
37242
+ return map;
37243
+ }
37208
37244
  function buildFieldTypeMap(fields) {
37209
37245
  const map = {};
37210
37246
  if (!fields) return map;
@@ -37256,6 +37292,8 @@ var init_DetailPanel = __esm({
37256
37292
  };
37257
37293
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
37258
37294
  const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
37295
+ const fieldLabelMap = isFieldDefArray(propFields) ? buildFieldLabelMap(propFields) : {};
37296
+ const labelFor = (field) => fieldLabelMap[field] ?? formatFieldLabel(field);
37259
37297
  const handleActionClick = React84.useCallback(
37260
37298
  (action, data2) => {
37261
37299
  if (action.navigatesTo) {
@@ -37291,7 +37329,7 @@ var init_DetailPanel = __esm({
37291
37329
  if (typeof field === "string") {
37292
37330
  const value = getNestedValue(normalizedData, field);
37293
37331
  return {
37294
- label: formatFieldLabel(field),
37332
+ label: labelFor(field),
37295
37333
  value: formatFieldValue(value, field),
37296
37334
  icon: getFieldIcon(field)
37297
37335
  };
@@ -37302,7 +37340,10 @@ var init_DetailPanel = __esm({
37302
37340
  }
37303
37341
  if (normalizedData && effectiveFieldNames) {
37304
37342
  const primaryField = effectiveFieldNames[0];
37305
- if (!title && primaryField && normalizedData[primaryField]) {
37343
+ const titleDerivedFromPrimary = Boolean(
37344
+ !title && primaryField && normalizedData[primaryField]
37345
+ );
37346
+ if (titleDerivedFromPrimary) {
37306
37347
  title = String(normalizedData[primaryField]);
37307
37348
  }
37308
37349
  const statusFields = effectiveFieldNames.filter(
@@ -37321,16 +37362,16 @@ var init_DetailPanel = __esm({
37321
37362
  (f3) => f3.toLowerCase().includes("description") || f3.toLowerCase().includes("note")
37322
37363
  );
37323
37364
  const otherFields = effectiveFieldNames.filter(
37324
- (f3) => f3 !== primaryField && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
37365
+ (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
37325
37366
  );
37326
37367
  sections = [];
37327
37368
  if (statusFields.length > 0 || otherFields.length > 0) {
37328
37369
  const overviewFields = [];
37329
- [...statusFields, ...otherFields.slice(0, 3)].forEach((field) => {
37370
+ [...statusFields, ...otherFields].forEach((field) => {
37330
37371
  const value = getNestedValue(normalizedData, field);
37331
37372
  if (value !== void 0 && value !== null) {
37332
37373
  overviewFields.push({
37333
- label: formatFieldLabel(field),
37374
+ label: labelFor(field),
37334
37375
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
37335
37376
  icon: getFieldIcon(field)
37336
37377
  });
@@ -37346,7 +37387,7 @@ var init_DetailPanel = __esm({
37346
37387
  const value = getNestedValue(normalizedData, field);
37347
37388
  if (value !== void 0 && value !== null) {
37348
37389
  metricsFields.push({
37349
- label: formatFieldLabel(field),
37390
+ label: labelFor(field),
37350
37391
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
37351
37392
  icon: getFieldIcon(field)
37352
37393
  });
@@ -37362,7 +37403,7 @@ var init_DetailPanel = __esm({
37362
37403
  const value = getNestedValue(normalizedData, field);
37363
37404
  if (value !== void 0 && value !== null) {
37364
37405
  timelineFields.push({
37365
- label: formatFieldLabel(field),
37406
+ label: labelFor(field),
37366
37407
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
37367
37408
  icon: getFieldIcon(field)
37368
37409
  });
@@ -37378,7 +37419,7 @@ var init_DetailPanel = __esm({
37378
37419
  const value = getNestedValue(normalizedData, field);
37379
37420
  if (value !== void 0 && value !== null) {
37380
37421
  descFields.push({
37381
- label: formatFieldLabel(field),
37422
+ label: labelFor(field),
37382
37423
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
37383
37424
  icon: getFieldIcon(field)
37384
37425
  });
@@ -37426,7 +37467,7 @@ var init_DetailPanel = __esm({
37426
37467
  if (typeof field === "string") {
37427
37468
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
37428
37469
  allFields.push({
37429
- label: formatFieldLabel(field),
37470
+ label: labelFor(field),
37430
37471
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
37431
37472
  icon: getFieldIcon(field)
37432
37473
  });
@@ -43929,6 +43970,13 @@ function MaybeTraitScope({
43929
43970
  if (wrap) {
43930
43971
  return /* @__PURE__ */ jsxRuntime.jsx(providers.TraitScopeProvider, { orbital, trait: sourceTrait, children });
43931
43972
  }
43973
+ if (sourceTrait !== void 0 && schemaCtx !== null) {
43974
+ scopeWrapLog.warn("decline", {
43975
+ sourceTrait,
43976
+ orbitalsByTraitSize: schemaCtx.orbitalsByTrait.size,
43977
+ reason: "sourceTrait not in orbitalsByTrait \u2014 children render unscoped"
43978
+ });
43979
+ }
43932
43980
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
43933
43981
  }
43934
43982
  function UISlotComponent({
@@ -44226,7 +44274,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
44226
44274
  const childId = `${parentId}-${index}`;
44227
44275
  const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
44228
44276
  const childAsRecord = child;
44229
- const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = childAsRecord;
44277
+ const { type: _childType, props: nestedProps, _id: _childNodeId, _sourceTrait: childSourceTrait, children: _childChildren, ...flatProps } = childAsRecord;
44230
44278
  const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
44231
44279
  if (_childChildren !== void 0 && nestedProps === void 0) {
44232
44280
  resolvedProps.children = _childChildren;
@@ -44241,11 +44289,14 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
44241
44289
  // (e.g. form-section inside a stack) can resolve entityDef via
44242
44290
  // the trait's linkedEntity for form-field enrichment. The orbCtx
44243
44291
  // (slot/transition/state/entity) propagates the same way so every
44244
- // nested node carries a complete contextual-edit address.
44245
- ...sourceTrait !== void 0 && { sourceTrait },
44292
+ // nested node carries a complete contextual-edit address. A child
44293
+ // carrying its own `_sourceTrait` (multi-source slot stack) owns it
44294
+ // outright — inheriting the synthetic wrapper's sentinel instead
44295
+ // would erase the real owner.
44296
+ ...childSourceTrait !== void 0 ? { sourceTrait: childSourceTrait } : sourceTrait !== void 0 && { sourceTrait },
44246
44297
  ...orbCtx ?? {}
44247
44298
  };
44248
- return /* @__PURE__ */ jsxRuntime.jsx(
44299
+ const renderedChild = /* @__PURE__ */ jsxRuntime.jsx(
44249
44300
  SlotContentRenderer,
44250
44301
  {
44251
44302
  content: childContent,
@@ -44254,6 +44305,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
44254
44305
  },
44255
44306
  childId
44256
44307
  );
44308
+ return childSourceTrait !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(MaybeTraitScope, { sourceTrait: childSourceTrait, children: renderedChild }, childId) : renderedChild;
44257
44309
  });
44258
44310
  }
44259
44311
  function toDrawableNodes(children) {
@@ -45536,6 +45588,28 @@ function extractRouteParams2(pattern, path) {
45536
45588
  function pathMatches2(pattern, path) {
45537
45589
  return matchPath2(pattern, path) !== null;
45538
45590
  }
45591
+ function comparePathSpecificity2(a, b) {
45592
+ const aParts = a.split("/").filter(Boolean);
45593
+ const bParts = b.split("/").filter(Boolean);
45594
+ const shared = Math.min(aParts.length, bParts.length);
45595
+ for (let i = 0; i < shared; i++) {
45596
+ const aParam = aParts[i].startsWith(":");
45597
+ const bParam = bParts[i].startsWith(":");
45598
+ if (aParam !== bParam) return aParam ? 1 : -1;
45599
+ }
45600
+ return 0;
45601
+ }
45602
+ function matchPathAmong2(candidates, path, pathOf) {
45603
+ const routed = candidates.filter((candidate) => Boolean(pathOf(candidate)));
45604
+ const ranked = [...routed].sort(
45605
+ (a, b) => comparePathSpecificity2(pathOf(a), pathOf(b))
45606
+ );
45607
+ for (const candidate of ranked) {
45608
+ const params = matchPath2(pathOf(candidate), path);
45609
+ if (params !== null) return { candidate, params };
45610
+ }
45611
+ return null;
45612
+ }
45539
45613
  function isInlineOrbital(orbital) {
45540
45614
  return "name" in orbital && typeof orbital.name === "string";
45541
45615
  }
@@ -45544,21 +45618,22 @@ function isInlinePage(page) {
45544
45618
  }
45545
45619
  function findPageByPath2(schema, path) {
45546
45620
  if (!schema.orbitals) return null;
45621
+ const candidates = [];
45547
45622
  for (const orbital of schema.orbitals) {
45548
45623
  if (!isInlineOrbital(orbital)) continue;
45549
45624
  if (!orbital.pages) continue;
45550
45625
  for (const pageRef of orbital.pages) {
45551
45626
  if (!isInlinePage(pageRef)) continue;
45552
- const page = pageRef;
45553
- const pagePath = page.path;
45554
- if (!pagePath) continue;
45555
- const params = matchPath2(pagePath, path);
45556
- if (params !== null) {
45557
- return { page, params, orbitalName: orbital.name };
45558
- }
45627
+ candidates.push({ page: pageRef, orbitalName: orbital.name });
45559
45628
  }
45560
45629
  }
45561
- return null;
45630
+ const hit = matchPathAmong2(candidates, path, (entry) => entry.page.path);
45631
+ if (!hit) return null;
45632
+ return {
45633
+ page: hit.candidate.page,
45634
+ params: hit.params,
45635
+ orbitalName: hit.candidate.orbitalName
45636
+ };
45562
45637
  }
45563
45638
  function findPageByName2(schema, pageName) {
45564
45639
  if (!schema.orbitals) return null;
@@ -46181,12 +46256,14 @@ exports.TraitScopeProvider = TraitScopeProvider3;
46181
46256
  exports.UserContext = UserContext;
46182
46257
  exports.UserProvider = UserProvider;
46183
46258
  exports.VerificationProvider = VerificationProvider;
46259
+ exports.comparePathSpecificity = comparePathSpecificity2;
46184
46260
  exports.extractRouteParams = extractRouteParams2;
46185
46261
  exports.findPageByName = findPageByName2;
46186
46262
  exports.findPageByPath = findPageByPath2;
46187
46263
  exports.getAllPages = getAllPages2;
46188
46264
  exports.getDefaultPage = getDefaultPage2;
46189
46265
  exports.matchPath = matchPath2;
46266
+ exports.matchPathAmong = matchPathAmong2;
46190
46267
  exports.pathMatches = pathMatches2;
46191
46268
  exports.useActivePage = useActivePage2;
46192
46269
  exports.useCurrentPagePath = useCurrentPagePath2;
@@ -3,8 +3,8 @@ import { EntityRow, FieldValue } from '@almadar/core';
3
3
  import { U as UIThemeDefinition } from '../UserContext-BKckAUv7.cjs';
4
4
  export { A as ANONYMOUS_USER, a as CurrentPagePathContext, b as CurrentPagePathProvider, c as CurrentPagePathProviderProps, d as DesignThemeProvider, O as OrbitalThemeProvider, e as OrbitalThemeProviderProps, h as UserContext, i as UserContextValue, j as UserData, k as UserProvider, l as UserProviderProps, u as useCurrentPagePath, m as useDesignTheme, n as useHasPermission, o as useHasRole, q as useUser, r as useUserForEvaluation } from '../UserContext-BKckAUv7.cjs';
5
5
  export { E as EntitySchemaContextValue, a as EntitySchemaProvider, b as EntitySchemaProviderProps, S as SendEventResult, c as ServerBridgeContextValue, d as ServerBridgeProvider, e as ServerBridgeProviderProps, f as ServerBridgeTransport, g as ServerClientEffect, h as ServerResponseMeta, T as TraitContext, i as TraitContextValue, j as TraitInstance, k as TraitProvider, l as TraitProviderProps, u as useEntitySchema, m as useEntitySchemaOptional, n as useServerBridge, o as useTrait, p as useTraitContext } from '../TraitProvider-Ch79cUcb.cjs';
6
- import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-aRuNznZx.cjs';
7
- export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as extractRouteParams, f as findPageByName, g as findPageByPath, h as getAllPages, i as getDefaultPage, m as matchPath, p as pathMatches, u as useActivePage, j as useInitPayload, k as useNavigateTo, l as useNavigation, n as useNavigationId, o as useNavigationState } from '../offline-executor-aRuNznZx.cjs';
6
+ import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-Qz4b6GpF.cjs';
7
+ export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as comparePathSpecificity, f as extractRouteParams, g as findPageByName, h as findPageByPath, i as getAllPages, j as getDefaultPage, m as matchPath, k as matchPathAmong, p as pathMatches, u as useActivePage, l as useInitPayload, n as useNavigateTo, o as useNavigation, q as useNavigationId, r as useNavigationState } from '../offline-executor-Qz4b6GpF.cjs';
8
8
  import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.cjs';
9
9
  export { G as GameAudioContext, a as GameAudioContextValue, b as GameAudioProvider, c as GameAudioProviderProps, u as useGameAudioContext, d as useGameAudioContextOptional } from '../GameAudioProvider-CPGwD49P.cjs';
10
10
  import '@almadar/core/patterns';
@@ -3,8 +3,8 @@ import { EntityRow, FieldValue } from '@almadar/core';
3
3
  import { U as UIThemeDefinition } from '../UserContext-BKckAUv7.js';
4
4
  export { A as ANONYMOUS_USER, a as CurrentPagePathContext, b as CurrentPagePathProvider, c as CurrentPagePathProviderProps, d as DesignThemeProvider, O as OrbitalThemeProvider, e as OrbitalThemeProviderProps, h as UserContext, i as UserContextValue, j as UserData, k as UserProvider, l as UserProviderProps, u as useCurrentPagePath, m as useDesignTheme, n as useHasPermission, o as useHasRole, q as useUser, r as useUserForEvaluation } from '../UserContext-BKckAUv7.js';
5
5
  export { E as EntitySchemaContextValue, a as EntitySchemaProvider, b as EntitySchemaProviderProps, S as SendEventResult, c as ServerBridgeContextValue, d as ServerBridgeProvider, e as ServerBridgeProviderProps, f as ServerBridgeTransport, g as ServerClientEffect, h as ServerResponseMeta, T as TraitContext, i as TraitContextValue, j as TraitInstance, k as TraitProvider, l as TraitProviderProps, u as useEntitySchema, m as useEntitySchemaOptional, n as useServerBridge, o as useTrait, p as useTraitContext } from '../TraitProvider-Ch79cUcb.js';
6
- import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-aRuNznZx.js';
7
- export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as extractRouteParams, f as findPageByName, g as findPageByPath, h as getAllPages, i as getDefaultPage, m as matchPath, p as pathMatches, u as useActivePage, j as useInitPayload, k as useNavigateTo, l as useNavigation, n as useNavigationId, o as useNavigationState } from '../offline-executor-aRuNznZx.js';
6
+ import { U as UseOfflineExecutorResult, a as UseOfflineExecutorOptions } from '../offline-executor-Qz4b6GpF.js';
7
+ export { N as NavigationContextValue, b as NavigationProvider, c as NavigationProviderProps, d as NavigationState, e as comparePathSpecificity, f as extractRouteParams, g as findPageByName, h as findPageByPath, i as getAllPages, j as getDefaultPage, m as matchPath, k as matchPathAmong, p as pathMatches, u as useActivePage, l as useInitPayload, n as useNavigateTo, o as useNavigation, q as useNavigationId, r as useNavigationState } from '../offline-executor-Qz4b6GpF.js';
8
8
  import { E as EventBusContextType } from '../event-bus-types-Bl78kokd.js';
9
9
  export { G as GameAudioContext, a as GameAudioContextValue, b as GameAudioProvider, c as GameAudioProviderProps, u as useGameAudioContext, d as useGameAudioContextOptional } from '../GameAudioProvider-CPGwD49P.js';
10
10
  import '@almadar/core/patterns';