@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.
@@ -14526,17 +14526,27 @@ function getWeekDays(start) {
14526
14526
  }
14527
14527
  return days;
14528
14528
  }
14529
- function generateDefaultTimeSlots() {
14529
+ function generateDefaultTimeSlots(events2) {
14530
+ let first = DEFAULT_FIRST_HOUR;
14531
+ let last = DEFAULT_LAST_HOUR;
14532
+ for (const ev of events2) {
14533
+ const start = new Date(ev.startTime);
14534
+ if (Number.isNaN(start.getTime())) continue;
14535
+ const hour = start.getHours();
14536
+ if (hour < first) first = hour;
14537
+ if (hour > last) last = hour;
14538
+ }
14530
14539
  const slots = [];
14531
- for (let hour = 9; hour <= 17; hour++) {
14532
- slots.push(`${hour.toString().padStart(2, "0")}:00`);
14540
+ for (let hour = first; hour <= last; hour++) {
14541
+ slots.push(slotLabel(hour));
14533
14542
  }
14534
14543
  return slots;
14535
14544
  }
14536
14545
  function eventInSlot(event, day, slotTime) {
14537
14546
  const eventStart = new Date(event.startTime);
14538
- const [slotHour, slotMinute] = slotTime.split(":").map(Number);
14539
- return eventStart.toDateString() === day.toDateString() && eventStart.getHours() === slotHour && eventStart.getMinutes() === slotMinute;
14547
+ if (Number.isNaN(eventStart.getTime())) return false;
14548
+ const [slotHour] = slotTime.split(":").map(Number);
14549
+ return eventStart.toDateString() === day.toDateString() && eventStart.getHours() === slotHour;
14540
14550
  }
14541
14551
  function CalendarGrid({
14542
14552
  weekStart,
@@ -14565,8 +14575,8 @@ function CalendarGrid({
14565
14575
  [resolvedWeekStart]
14566
14576
  );
14567
14577
  const resolvedTimeSlots = useMemo(
14568
- () => timeSlots ?? generateDefaultTimeSlots(),
14569
- [timeSlots]
14578
+ () => timeSlots ?? generateDefaultTimeSlots(evs),
14579
+ [timeSlots, evs]
14570
14580
  );
14571
14581
  const visibleCount = useDayWindow(dayWindow);
14572
14582
  const [dayOffset, setDayOffset] = useState(0);
@@ -14753,7 +14763,7 @@ function CalendarGrid({
14753
14763
  }
14754
14764
  );
14755
14765
  }
14756
- var SHORT_DATE;
14766
+ var SHORT_DATE, DEFAULT_FIRST_HOUR, DEFAULT_LAST_HOUR, slotLabel;
14757
14767
  var init_CalendarGrid = __esm({
14758
14768
  "components/core/molecules/CalendarGrid.tsx"() {
14759
14769
  "use client";
@@ -14768,6 +14778,9 @@ var init_CalendarGrid = __esm({
14768
14778
  init_useEventBus();
14769
14779
  init_useSwipeGesture();
14770
14780
  SHORT_DATE = { month: "short", day: "numeric" };
14781
+ DEFAULT_FIRST_HOUR = 9;
14782
+ DEFAULT_LAST_HOUR = 17;
14783
+ slotLabel = (hour) => `${hour.toString().padStart(2, "0")}:00`;
14771
14784
  CalendarGrid.displayName = "CalendarGrid";
14772
14785
  }
14773
14786
  });
@@ -20820,13 +20833,13 @@ function DataGrid({
20820
20833
  }
20821
20834
  ),
20822
20835
  /* @__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: [
20836
+ titleValue !== void 0 && titleValue !== null && /* @__PURE__ */ jsxs(HStack, { gap: "xs", className: "items-center min-w-0", children: [
20824
20837
  titleField?.icon && renderIconInput(titleField.icon, { size: "sm", className: "text-primary flex-shrink-0" }),
20825
20838
  /* @__PURE__ */ jsx(
20826
20839
  Typography,
20827
20840
  {
20828
20841
  variant: titleField?.variant === "h3" ? "h3" : "h4",
20829
- className: "font-semibold truncate",
20842
+ className: "font-semibold truncate min-w-0",
20830
20843
  children: String(titleValue)
20831
20844
  }
20832
20845
  )
@@ -20884,7 +20897,7 @@ function DataGrid({
20884
20897
  )
20885
20898
  ] }, field.name);
20886
20899
  }) }) }),
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: [
20900
+ 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
20901
  (maxInlineActions != null ? primaryActions.slice(0, maxInlineActions) : primaryActions).map((action, idx) => /* @__PURE__ */ jsxs(
20889
20902
  Button,
20890
20903
  {
@@ -29551,7 +29564,7 @@ function TableView({
29551
29564
  col.key
29552
29565
  );
29553
29566
  }),
29554
- hasActions && /* @__PURE__ */ jsx(Box, { "aria-hidden": true })
29567
+ hasActions && /* @__PURE__ */ jsx(Box, { "aria-hidden": true, className: "sticky right-0 bg-[var(--color-surface-subtle)]" })
29555
29568
  ]
29556
29569
  }
29557
29570
  );
@@ -29595,41 +29608,54 @@ function TableView({
29595
29608
  }
29596
29609
  return /* @__PURE__ */ jsx(Box, { role: "cell", className: cellBase, children: /* @__PURE__ */ jsx("span", { className: "truncate", children: formatCell(raw, col.format) }) }, col.key);
29597
29610
  }),
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
- ] })
29611
+ itemActions && itemActions.length > 0 && /* @__PURE__ */ jsxs(
29612
+ HStack,
29613
+ {
29614
+ gap: "xs",
29615
+ className: cn(
29616
+ // Pinned: the fixed column tracks routinely overflow the caller's
29617
+ // scroll container, which used to leave the actions off-screen.
29618
+ // Opaque so scrolled cells pass underneath it.
29619
+ "justify-end flex-shrink-0 sticky right-0 z-[1] transition-colors",
29620
+ lk.striped && index % 2 === 1 ? "bg-[var(--color-surface-subtle)]" : "bg-[var(--color-card)] group-hover:bg-[var(--color-surface-subtle)]"
29621
+ ),
29622
+ children: [
29623
+ (maxInlineActions != null ? itemActions.slice(0, maxInlineActions) : itemActions).map((action, i) => /* @__PURE__ */ jsxs(
29624
+ Button,
29625
+ {
29626
+ variant: action.variant ?? "ghost",
29627
+ size: "sm",
29628
+ onClick: handleActionClick(action, row),
29629
+ "data-testid": `action-${action.event}`,
29630
+ "data-row-id": String(row.id),
29631
+ className: cn(action.variant === "danger" && "text-error hover:bg-error/10"),
29632
+ children: [
29633
+ action.icon && renderIconInput3(action.icon, { size: "xs", className: "mr-1" }),
29634
+ action.label
29635
+ ]
29636
+ },
29637
+ i
29638
+ )),
29639
+ maxInlineActions != null && itemActions.length > maxInlineActions && /* @__PURE__ */ jsx(
29640
+ Menu,
29641
+ {
29642
+ position: "bottom-end",
29643
+ 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" }) }),
29644
+ items: itemActions.slice(maxInlineActions).map((action) => ({
29645
+ label: action.label,
29646
+ icon: action.icon,
29647
+ event: action.event,
29648
+ variant: action.variant === "danger" ? "danger" : "default",
29649
+ onClick: () => eventBus.emit(`UI:${action.event}`, {
29650
+ id: row.id,
29651
+ row
29652
+ })
29653
+ }))
29654
+ }
29655
+ )
29656
+ ]
29657
+ }
29658
+ )
29633
29659
  ]
29634
29660
  }
29635
29661
  );
@@ -38582,6 +38608,16 @@ function normalizeFieldDefs(fields) {
38582
38608
  return String(f3);
38583
38609
  });
38584
38610
  }
38611
+ function buildFieldLabelMap(fields) {
38612
+ const map = {};
38613
+ if (!fields) return map;
38614
+ for (const f3 of fields) {
38615
+ if (typeof f3 === "object" && "key" in f3 && f3.header !== void 0 && f3.header !== "") {
38616
+ map[f3.key] = f3.header;
38617
+ }
38618
+ }
38619
+ return map;
38620
+ }
38585
38621
  function buildFieldTypeMap(fields) {
38586
38622
  const map = {};
38587
38623
  if (!fields) return map;
@@ -38633,6 +38669,8 @@ var init_DetailPanel = __esm({
38633
38669
  };
38634
38670
  const effectiveFieldNames = isFieldDefArray(propFields) ? normalizeFieldDefs(propFields) : fieldNames;
38635
38671
  const fieldTypeMap = isFieldDefArray(propFields) ? buildFieldTypeMap(propFields) : {};
38672
+ const fieldLabelMap = isFieldDefArray(propFields) ? buildFieldLabelMap(propFields) : {};
38673
+ const labelFor = (field) => fieldLabelMap[field] ?? formatFieldLabel(field);
38636
38674
  const handleActionClick = useCallback(
38637
38675
  (action, data2) => {
38638
38676
  if (action.navigatesTo) {
@@ -38668,7 +38706,7 @@ var init_DetailPanel = __esm({
38668
38706
  if (typeof field === "string") {
38669
38707
  const value = getNestedValue(normalizedData, field);
38670
38708
  return {
38671
- label: formatFieldLabel(field),
38709
+ label: labelFor(field),
38672
38710
  value: formatFieldValue(value, field),
38673
38711
  icon: getFieldIcon(field)
38674
38712
  };
@@ -38679,7 +38717,10 @@ var init_DetailPanel = __esm({
38679
38717
  }
38680
38718
  if (normalizedData && effectiveFieldNames) {
38681
38719
  const primaryField = effectiveFieldNames[0];
38682
- if (!title && primaryField && normalizedData[primaryField]) {
38720
+ const titleDerivedFromPrimary = Boolean(
38721
+ !title && primaryField && normalizedData[primaryField]
38722
+ );
38723
+ if (titleDerivedFromPrimary) {
38683
38724
  title = String(normalizedData[primaryField]);
38684
38725
  }
38685
38726
  const statusFields = effectiveFieldNames.filter(
@@ -38698,16 +38739,16 @@ var init_DetailPanel = __esm({
38698
38739
  (f3) => f3.toLowerCase().includes("description") || f3.toLowerCase().includes("note")
38699
38740
  );
38700
38741
  const otherFields = effectiveFieldNames.filter(
38701
- (f3) => f3 !== primaryField && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
38742
+ (f3) => (!titleDerivedFromPrimary || f3 !== primaryField) && !statusFields.includes(f3) && !progressFields.includes(f3) && !metricFields.includes(f3) && !dateFields.includes(f3) && !descriptionFields.includes(f3)
38702
38743
  );
38703
38744
  sections = [];
38704
38745
  if (statusFields.length > 0 || otherFields.length > 0) {
38705
38746
  const overviewFields = [];
38706
- [...statusFields, ...otherFields.slice(0, 3)].forEach((field) => {
38747
+ [...statusFields, ...otherFields].forEach((field) => {
38707
38748
  const value = getNestedValue(normalizedData, field);
38708
38749
  if (value !== void 0 && value !== null) {
38709
38750
  overviewFields.push({
38710
- label: formatFieldLabel(field),
38751
+ label: labelFor(field),
38711
38752
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38712
38753
  icon: getFieldIcon(field)
38713
38754
  });
@@ -38723,7 +38764,7 @@ var init_DetailPanel = __esm({
38723
38764
  const value = getNestedValue(normalizedData, field);
38724
38765
  if (value !== void 0 && value !== null) {
38725
38766
  metricsFields.push({
38726
- label: formatFieldLabel(field),
38767
+ label: labelFor(field),
38727
38768
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38728
38769
  icon: getFieldIcon(field)
38729
38770
  });
@@ -38739,7 +38780,7 @@ var init_DetailPanel = __esm({
38739
38780
  const value = getNestedValue(normalizedData, field);
38740
38781
  if (value !== void 0 && value !== null) {
38741
38782
  timelineFields.push({
38742
- label: formatFieldLabel(field),
38783
+ label: labelFor(field),
38743
38784
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38744
38785
  icon: getFieldIcon(field)
38745
38786
  });
@@ -38755,7 +38796,7 @@ var init_DetailPanel = __esm({
38755
38796
  const value = getNestedValue(normalizedData, field);
38756
38797
  if (value !== void 0 && value !== null) {
38757
38798
  descFields.push({
38758
- label: formatFieldLabel(field),
38799
+ label: labelFor(field),
38759
38800
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38760
38801
  icon: getFieldIcon(field)
38761
38802
  });
@@ -38803,7 +38844,7 @@ var init_DetailPanel = __esm({
38803
38844
  if (typeof field === "string") {
38804
38845
  const value = normalizedData ? getNestedValue(normalizedData, field) : void 0;
38805
38846
  allFields.push({
38806
- label: formatFieldLabel(field),
38847
+ label: labelFor(field),
38807
38848
  value: renderRichFieldValue(value, field, fieldTypeMap[field]),
38808
38849
  icon: getFieldIcon(field)
38809
38850
  });
@@ -45306,6 +45347,13 @@ function MaybeTraitScope({
45306
45347
  if (wrap) {
45307
45348
  return /* @__PURE__ */ jsx(TraitScopeProvider, { orbital, trait: sourceTrait, children });
45308
45349
  }
45350
+ if (sourceTrait !== void 0 && schemaCtx !== null) {
45351
+ scopeWrapLog.warn("decline", {
45352
+ sourceTrait,
45353
+ orbitalsByTraitSize: schemaCtx.orbitalsByTrait.size,
45354
+ reason: "sourceTrait not in orbitalsByTrait \u2014 children render unscoped"
45355
+ });
45356
+ }
45309
45357
  return /* @__PURE__ */ jsx(Fragment, { children });
45310
45358
  }
45311
45359
  function UISlotComponent({
@@ -45603,7 +45651,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
45603
45651
  const childId = `${parentId}-${index}`;
45604
45652
  const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
45605
45653
  const childAsRecord = child;
45606
- const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = childAsRecord;
45654
+ const { type: _childType, props: nestedProps, _id: _childNodeId, _sourceTrait: childSourceTrait, children: _childChildren, ...flatProps } = childAsRecord;
45607
45655
  const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
45608
45656
  if (_childChildren !== void 0 && nestedProps === void 0) {
45609
45657
  resolvedProps.children = _childChildren;
@@ -45618,11 +45666,14 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
45618
45666
  // (e.g. form-section inside a stack) can resolve entityDef via
45619
45667
  // the trait's linkedEntity for form-field enrichment. The orbCtx
45620
45668
  // (slot/transition/state/entity) propagates the same way so every
45621
- // nested node carries a complete contextual-edit address.
45622
- ...sourceTrait !== void 0 && { sourceTrait },
45669
+ // nested node carries a complete contextual-edit address. A child
45670
+ // carrying its own `_sourceTrait` (multi-source slot stack) owns it
45671
+ // outright — inheriting the synthetic wrapper's sentinel instead
45672
+ // would erase the real owner.
45673
+ ...childSourceTrait !== void 0 ? { sourceTrait: childSourceTrait } : sourceTrait !== void 0 && { sourceTrait },
45623
45674
  ...orbCtx ?? {}
45624
45675
  };
45625
- return /* @__PURE__ */ jsx(
45676
+ const renderedChild = /* @__PURE__ */ jsx(
45626
45677
  SlotContentRenderer,
45627
45678
  {
45628
45679
  content: childContent,
@@ -45631,6 +45682,7 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
45631
45682
  },
45632
45683
  childId
45633
45684
  );
45685
+ return childSourceTrait !== void 0 ? /* @__PURE__ */ jsx(MaybeTraitScope, { sourceTrait: childSourceTrait, children: renderedChild }, childId) : renderedChild;
45634
45686
  });
45635
45687
  }
45636
45688
  function toDrawableNodes(children) {
@@ -47179,9 +47231,10 @@ function aggregateSlot(sources) {
47179
47231
  const entries = Object.entries(sources);
47180
47232
  if (entries.length === 0) return null;
47181
47233
  if (entries.length === 1) return entries[0][1];
47182
- const children = entries.map(([, entry]) => ({
47234
+ const children = entries.map(([sourceKey, entry]) => ({
47183
47235
  type: entry.pattern,
47184
- ...entry.props
47236
+ ...entry.props,
47237
+ ...sourceKey !== DEFAULT_SOURCE_KEY && { _sourceTrait: sourceKey }
47185
47238
  }));
47186
47239
  const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
47187
47240
  return {
@@ -40,9 +40,10 @@ function aggregateSlot(sources) {
40
40
  const entries = Object.entries(sources);
41
41
  if (entries.length === 0) return null;
42
42
  if (entries.length === 1) return entries[0][1];
43
- const children = entries.map(([, entry]) => ({
43
+ const children = entries.map(([sourceKey, entry]) => ({
44
44
  type: entry.pattern,
45
- ...entry.props
45
+ ...entry.props,
46
+ ...sourceKey !== DEFAULT_SOURCE_KEY && { _sourceTrait: sourceKey }
46
47
  }));
47
48
  const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
48
49
  return {
@@ -38,9 +38,10 @@ function aggregateSlot(sources) {
38
38
  const entries = Object.entries(sources);
39
39
  if (entries.length === 0) return null;
40
40
  if (entries.length === 1) return entries[0][1];
41
- const children = entries.map(([, entry]) => ({
41
+ const children = entries.map(([sourceKey, entry]) => ({
42
42
  type: entry.pattern,
43
- ...entry.props
43
+ ...entry.props,
44
+ ...sourceKey !== DEFAULT_SOURCE_KEY && { _sourceTrait: sourceKey }
44
45
  }));
45
46
  const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
46
47
  return {
@@ -1053,9 +1053,10 @@ function aggregateSlot(sources) {
1053
1053
  const entries = Object.entries(sources);
1054
1054
  if (entries.length === 0) return null;
1055
1055
  if (entries.length === 1) return entries[0][1];
1056
- const children = entries.map(([, entry]) => ({
1056
+ const children = entries.map(([sourceKey, entry]) => ({
1057
1057
  type: entry.pattern,
1058
- ...entry.props
1058
+ ...entry.props,
1059
+ ...sourceKey !== DEFAULT_SOURCE_KEY && { _sourceTrait: sourceKey }
1059
1060
  }));
1060
1061
  const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
1061
1062
  return {
@@ -1051,9 +1051,10 @@ function aggregateSlot(sources) {
1051
1051
  const entries = Object.entries(sources);
1052
1052
  if (entries.length === 0) return null;
1053
1053
  if (entries.length === 1) return entries[0][1];
1054
- const children = entries.map(([, entry]) => ({
1054
+ const children = entries.map(([sourceKey, entry]) => ({
1055
1055
  type: entry.pattern,
1056
- ...entry.props
1056
+ ...entry.props,
1057
+ ...sourceKey !== DEFAULT_SOURCE_KEY && { _sourceTrait: sourceKey }
1057
1058
  }));
1058
1059
  const stackId = `slot-content-stack-${entries.map(([k]) => k).join("-")}`;
1059
1060
  return {