@hjmds/react-native 1.33.2 → 1.35.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.
Files changed (174) hide show
  1. package/dist/actions.d.ts +12 -72
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +1 -1
  4. package/dist/actions.js.map +1 -1
  5. package/dist/auth-screen.d.ts.map +1 -1
  6. package/dist/auth-screen.js +3 -2
  7. package/dist/auth-screen.js.map +1 -1
  8. package/dist/calendar.d.ts.map +1 -1
  9. package/dist/calendar.js.map +1 -1
  10. package/dist/carousel.d.ts +10 -2
  11. package/dist/carousel.d.ts.map +1 -1
  12. package/dist/carousel.js +12 -6
  13. package/dist/carousel.js.map +1 -1
  14. package/dist/collapsible.d.ts +7 -1
  15. package/dist/collapsible.d.ts.map +1 -1
  16. package/dist/collapsible.js +14 -12
  17. package/dist/collapsible.js.map +1 -1
  18. package/dist/collection-editing.d.ts.map +1 -1
  19. package/dist/collection-editing.js.map +1 -1
  20. package/dist/collection-rail.d.ts +4 -4
  21. package/dist/collection-rail.d.ts.map +1 -1
  22. package/dist/collection-rail.js.map +1 -1
  23. package/dist/communication.d.ts.map +1 -1
  24. package/dist/communication.js.map +1 -1
  25. package/dist/conversation-row.d.ts.map +1 -1
  26. package/dist/conversation-row.js +4 -1
  27. package/dist/conversation-row.js.map +1 -1
  28. package/dist/data-display.d.ts +63 -8
  29. package/dist/data-display.d.ts.map +1 -1
  30. package/dist/data-display.js +140 -99
  31. package/dist/data-display.js.map +1 -1
  32. package/dist/data-table.d.ts +3 -1
  33. package/dist/data-table.d.ts.map +1 -1
  34. package/dist/data-table.js +15 -3
  35. package/dist/data-table.js.map +1 -1
  36. package/dist/date-picker.d.ts.map +1 -1
  37. package/dist/date-picker.js +1 -1
  38. package/dist/date-picker.js.map +1 -1
  39. package/dist/effect-surface.js.map +1 -1
  40. package/dist/evidence.d.ts +1 -1
  41. package/dist/evidence.d.ts.map +1 -1
  42. package/dist/evidence.js +2 -1
  43. package/dist/evidence.js.map +1 -1
  44. package/dist/feedback.d.ts +6 -1
  45. package/dist/feedback.d.ts.map +1 -1
  46. package/dist/feedback.js +7 -5
  47. package/dist/feedback.js.map +1 -1
  48. package/dist/floating-action-button.d.ts +3 -12
  49. package/dist/floating-action-button.d.ts.map +1 -1
  50. package/dist/floating-action-button.js +1 -1
  51. package/dist/floating-action-button.js.map +1 -1
  52. package/dist/forms.d.ts +2 -1
  53. package/dist/forms.d.ts.map +1 -1
  54. package/dist/forms.js +36 -3
  55. package/dist/forms.js.map +1 -1
  56. package/dist/image-choice.d.ts.map +1 -1
  57. package/dist/image-choice.js +8 -6
  58. package/dist/image-choice.js.map +1 -1
  59. package/dist/image-viewer.d.ts.map +1 -1
  60. package/dist/image-viewer.js +7 -4
  61. package/dist/image-viewer.js.map +1 -1
  62. package/dist/index.d.ts +4 -3
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +3 -2
  65. package/dist/index.js.map +1 -1
  66. package/dist/inputs.d.ts +26 -8
  67. package/dist/inputs.d.ts.map +1 -1
  68. package/dist/inputs.js +102 -51
  69. package/dist/inputs.js.map +1 -1
  70. package/dist/internal/accessible-focus.d.ts +2 -1
  71. package/dist/internal/accessible-focus.d.ts.map +1 -1
  72. package/dist/internal/accessible-focus.js +1 -1
  73. package/dist/internal/accessible-focus.js.map +1 -1
  74. package/dist/internal/field-frame.d.ts +8 -4
  75. package/dist/internal/field-frame.d.ts.map +1 -1
  76. package/dist/internal/field-frame.js +6 -6
  77. package/dist/internal/field-frame.js.map +1 -1
  78. package/dist/internal/field-private.d.ts +1 -0
  79. package/dist/internal/field-private.d.ts.map +1 -1
  80. package/dist/internal/field-visibility.d.ts +6 -0
  81. package/dist/internal/field-visibility.d.ts.map +1 -0
  82. package/dist/internal/field-visibility.js +13 -0
  83. package/dist/internal/field-visibility.js.map +1 -0
  84. package/dist/internal/initial-focus.d.ts +8 -1
  85. package/dist/internal/initial-focus.d.ts.map +1 -1
  86. package/dist/internal/initial-focus.js +17 -8
  87. package/dist/internal/initial-focus.js.map +1 -1
  88. package/dist/internal/message-reactions.d.ts.map +1 -1
  89. package/dist/internal/message-reactions.js.map +1 -1
  90. package/dist/internal/modal-lifecycle.d.ts.map +1 -1
  91. package/dist/internal/modal-lifecycle.js +5 -2
  92. package/dist/internal/modal-lifecycle.js.map +1 -1
  93. package/dist/internal/pending-content.d.ts +11 -0
  94. package/dist/internal/pending-content.d.ts.map +1 -0
  95. package/dist/internal/pending-content.js +16 -0
  96. package/dist/internal/pending-content.js.map +1 -0
  97. package/dist/internal/recipe-button.d.ts +8 -31
  98. package/dist/internal/recipe-button.d.ts.map +1 -1
  99. package/dist/internal/recipe-button.js +49 -12
  100. package/dist/internal/recipe-button.js.map +1 -1
  101. package/dist/internal/screen-dismiss.d.ts +10 -0
  102. package/dist/internal/screen-dismiss.d.ts.map +1 -0
  103. package/dist/internal/screen-dismiss.js +62 -0
  104. package/dist/internal/screen-dismiss.js.map +1 -0
  105. package/dist/internal/screen-footer.d.ts +1 -1
  106. package/dist/internal/text-align.d.ts +2 -2
  107. package/dist/internal/text-align.d.ts.map +1 -1
  108. package/dist/keyboard.d.ts +3 -2
  109. package/dist/keyboard.d.ts.map +1 -1
  110. package/dist/keyboard.js +3 -1
  111. package/dist/keyboard.js.map +1 -1
  112. package/dist/mentions.js.map +1 -1
  113. package/dist/navigation.d.ts +3 -1
  114. package/dist/navigation.d.ts.map +1 -1
  115. package/dist/navigation.js +31 -10
  116. package/dist/navigation.js.map +1 -1
  117. package/dist/number-field.d.ts +3 -26
  118. package/dist/number-field.d.ts.map +1 -1
  119. package/dist/number-field.js +2 -1
  120. package/dist/number-field.js.map +1 -1
  121. package/dist/overlays.d.ts +11 -6
  122. package/dist/overlays.d.ts.map +1 -1
  123. package/dist/overlays.js +19 -14
  124. package/dist/overlays.js.map +1 -1
  125. package/dist/primitives.d.ts +5 -31
  126. package/dist/primitives.d.ts.map +1 -1
  127. package/dist/primitives.js.map +1 -1
  128. package/dist/provider.d.ts.map +1 -1
  129. package/dist/provider.js +9 -2
  130. package/dist/provider.js.map +1 -1
  131. package/dist/public-exports.generated.d.ts +6 -0
  132. package/dist/public-exports.generated.d.ts.map +1 -1
  133. package/dist/public-exports.generated.js +18 -0
  134. package/dist/public-exports.generated.js.map +1 -1
  135. package/dist/screen-flows.d.ts +13 -6
  136. package/dist/screen-flows.d.ts.map +1 -1
  137. package/dist/screen-flows.js +26 -15
  138. package/dist/screen-flows.js.map +1 -1
  139. package/dist/screens.d.ts +34 -9
  140. package/dist/screens.d.ts.map +1 -1
  141. package/dist/screens.js +37 -15
  142. package/dist/screens.js.map +1 -1
  143. package/dist/sheet-gesture.d.ts +5 -2
  144. package/dist/sheet-gesture.d.ts.map +1 -1
  145. package/dist/sheet-gesture.js.map +1 -1
  146. package/dist/sheet-panel.d.ts +24 -0
  147. package/dist/sheet-panel.d.ts.map +1 -0
  148. package/dist/sheet-panel.js +111 -0
  149. package/dist/sheet-panel.js.map +1 -0
  150. package/dist/shortcut-rail.d.ts +28 -0
  151. package/dist/shortcut-rail.d.ts.map +1 -0
  152. package/dist/shortcut-rail.js +50 -0
  153. package/dist/shortcut-rail.js.map +1 -0
  154. package/dist/slider.d.ts +3 -20
  155. package/dist/slider.d.ts.map +1 -1
  156. package/dist/slider.js.map +1 -1
  157. package/dist/status-text.d.ts +3 -6
  158. package/dist/status-text.d.ts.map +1 -1
  159. package/dist/status-text.js.map +1 -1
  160. package/dist/steps.d.ts +2 -1
  161. package/dist/steps.d.ts.map +1 -1
  162. package/dist/steps.js +8 -5
  163. package/dist/steps.js.map +1 -1
  164. package/dist/table-family.d.ts.map +1 -1
  165. package/dist/table-family.js.map +1 -1
  166. package/dist/task-list.d.ts +3 -1
  167. package/dist/task-list.d.ts.map +1 -1
  168. package/dist/task-list.js +2 -2
  169. package/dist/task-list.js.map +1 -1
  170. package/dist/time-picker.d.ts +9 -0
  171. package/dist/time-picker.d.ts.map +1 -0
  172. package/dist/time-picker.js +59 -0
  173. package/dist/time-picker.js.map +1 -0
  174. package/package.json +44 -25
@@ -19,18 +19,16 @@ import { minimumTargetStyle } from "./internal/styles.js";
19
19
  import { webDisclosureProps, webOnly } from "./internal/web-a11y.js";
20
20
  import { Surface, Text, } from "./primitives.js";
21
21
  import { useHjmNativeTheme } from "./provider.js";
22
- export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRecipe.defaults.size, variant = badgeRecipe.defaults.variant, leading, accessibilityLabel, layoutStyle, ...props }) {
22
+ export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRecipe.defaults.size, variant = badgeRecipe.defaults.variant, leading, trailing, accessibilityLabel, layoutStyle, ...props }) {
23
23
  assertNoRemovedStyleProps("Badge", props, ["style", "labelStyle"]);
24
24
  const theme = useHjmNativeTheme();
25
25
  const presentation = badgeRecipe.tones[tone];
26
26
  const metrics = badgeRecipe.sizes[size];
27
27
  const variantPresentation = badgeRecipe.variants[variant];
28
28
  const outlined = !variantPresentation.usesToneBackground;
29
- const borderColor = presentation.border
30
- ? resolveColorReference(presentation.border, theme.palette)
31
- : variantPresentation.borderFallback === null
32
- ? "transparent"
33
- : resolveColorReference(variantPresentation.borderFallback, theme.palette);
29
+ const iconContext = { color: resolveColorReference(outlined ? presentation.outlineContent : presentation.content, theme.palette), size: metrics.iconSize };
30
+ const borderReference = outlined ? presentation.border ?? variantPresentation.borderFallback : null;
31
+ const borderColor = borderReference === null ? "transparent" : resolveColorReference(borderReference, theme.palette);
34
32
  return (_jsxs(View, { ...props, accessibilityLabel: accessibilityLabel ?? String(label), accessible: true, style: [
35
33
  {
36
34
  alignSelf: "flex-start",
@@ -40,9 +38,7 @@ export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRec
40
38
  : resolveColorReference(presentation.background, theme.palette),
41
39
  borderColor,
42
40
  borderRadius: theme.tokens.radius[badgeRecipe.radius],
43
- borderWidth: presentation.border || variantPresentation.borderFallback
44
- ? badgeRecipe.borderWidth
45
- : 0,
41
+ borderWidth: borderReference === null ? 0 : badgeRecipe.borderWidth,
46
42
  direction: theme.environment.direction,
47
43
  flexDirection: "row",
48
44
  gap: metrics.gap,
@@ -51,11 +47,12 @@ export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRec
51
47
  paddingHorizontal: metrics.paddingHorizontal,
52
48
  },
53
49
  layoutStyle,
54
- ], children: [leading === undefined ? null : (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", children: leading })), _jsx(Text, { accessible: false, align: "center", emphasis: "strong", style: [
50
+ ], children: [leading === undefined ? null : (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", children: typeof leading === "function" ? leading(iconContext) : leading })), _jsx(Text, { accessible: false, align: "center", emphasis: "strong", style: [
55
51
  {
52
+ fontWeight: badgeRecipe.fontWeight,
56
53
  color: resolveColorReference(outlined ? presentation.outlineContent : presentation.content, theme.palette),
57
54
  },
58
- ], variant: metrics.textVariant, children: label })] }));
55
+ ], variant: metrics.textVariant, children: label }), trailing === undefined ? null : (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", children: typeof trailing === "function" ? trailing(iconContext) : trailing }))] }));
59
56
  }
60
57
  export function Tag({ children, tone, accessibilityLabel, layoutStyle, ...props }) {
61
58
  assertNoRemovedStyleProps("Tag", props, ["style", "labelStyle"]);
@@ -86,15 +83,24 @@ export function Tag({ children, tone, accessibilityLabel, layoutStyle, ...props
86
83
  layoutStyle,
87
84
  ], children: _jsx(Text, { align: "center", emphasis: "medium", style: [{ color: presentation.content }], variant: tagRecipe.size.textVariant, children: descriptor.label }) }));
88
85
  }
89
- export function Card({ children, title, description, leading, media, actions, selected = cardRecipe.defaults.selected, onActivate, disabled = false, accessibilityLabel, accessibilityHint, tone = cardRecipe.defaults.tone, bordered = cardRecipe.defaults.bordered, padding = cardRecipe.defaults.padding, layoutStyle, radius: cornerRadius = surfaceDefaults.radius, ...props }) {
90
- const { environment, tokens } = useHjmNativeTheme();
86
+ export function Card({ children, title, description, leading, media, backgroundMedia, backgroundInteraction, mediaBadges, badges, mediaAction, actions, headerActions, selected = cardRecipe.defaults.selected, onActivate, disabled = false, accessibilityLabel, accessibilityHint, tone = cardRecipe.defaults.tone, bordered = cardRecipe.defaults.bordered, padding = cardRecipe.defaults.padding, layoutStyle, radius: cornerRadius = surfaceDefaults.radius, ...props }) {
87
+ const { environment, tokens, colors } = useHjmNativeTheme();
91
88
  if (onActivate && !accessibilityLabel?.trim()) {
92
89
  throw new TypeError("Interactive Card requires accessibilityLabel");
93
90
  }
91
+ if (mediaAction && (onActivate || !media || !mediaAction.label.trim()))
92
+ throw new TypeError("Card mediaAction requires passive media, a label, and no whole-card onActivate");
93
+ if (backgroundMedia && (media || mediaAction || onActivate))
94
+ throw new TypeError("Card backgroundMedia is decorative and cannot combine with media, mediaAction or onActivate");
95
+ if ((backgroundInteraction !== undefined || mediaBadges !== undefined) && !backgroundMedia)
96
+ throw new TypeError("Card backgroundInteraction/mediaBadges require backgroundMedia");
97
+ const [headerActionSize, setHeaderActionSize] = useState({ width: 0, height: 0 });
98
+ const [headerBodyTop, setHeaderBodyTop] = useState(0);
99
+ const [headerRow, setHeaderRow] = useState(null);
94
100
  const bodyPadding = surfaceGeometry.paddings[padding];
95
- const hasHeader = leading !== undefined || title !== undefined || description !== undefined;
101
+ const hasHeader = leading !== undefined || title !== undefined || description !== undefined || headerActions !== undefined;
96
102
  // Whole-card open plus separate commands (2026-10-18 unairplane journey card: open + delete); see `onActivate`.
97
- const split = onActivate !== undefined && actions !== undefined && actions !== null && actions !== false;
103
+ const split = onActivate !== undefined && Boolean(actions || headerActions);
98
104
  const activate = () => { if (!disabled)
99
105
  onActivate?.(); };
100
106
  const activationA11y = {
@@ -104,15 +110,22 @@ export function Card({ children, title, description, leading, media, actions, se
104
110
  accessibilityState: { selected, disabled },
105
111
  };
106
112
  const feedbackOpacity = (pressed) => disabled ? cardRecipe.interaction.disabledOpacity : pressed ? cardRecipe.interaction.pressedOpacity : 1;
107
- const frame = (_jsx(Surface, { ...props, bordered: bordered, padding: "none", radius: cornerRadius, ...(onActivate ? {} : { accessibilityLabel, accessibilityHint }), ...(layoutStyle === undefined || (onActivate && !split) ? {} : { layoutStyle }), tone: selected ? cardRecipe.selectedTone : tone, children: _jsxs(View, { style: {
113
+ // The activation host owns placement; its inner frame/body fill a stretched collection slot.
114
+ const frame = (_jsx(Surface, { ...props, bordered: bordered, padding: "none", radius: cornerRadius, ...(onActivate ? {} : { accessibilityLabel, accessibilityHint }), ...(onActivate && !split ? { layoutStyle: { flexGrow: 1 } } : layoutStyle === undefined ? {} : { layoutStyle }), tone: selected ? cardRecipe.selectedTone : tone, children: _jsxs(View, { pointerEvents: backgroundMedia ? "box-none" : "auto", style: {
108
115
  overflow: "hidden",
116
+ flexGrow: 1,
109
117
  borderRadius: tokens.radius[cornerRadius],
110
- }, children: [_jsxs(CardActivationRegion, { split: split, activation: activationA11y, disabled: disabled, onPress: activate, feedbackOpacity: feedbackOpacity, children: [media === undefined ? null : _jsx(View, { children: media }), _jsxs(View, { style: { gap: cardRecipe.body.gap, padding: bodyPadding }, children: [hasHeader ? (_jsxs(View, { style: {
111
- alignItems: "flex-start",
118
+ ...(backgroundMedia ? { flex: 1, justifyContent: "flex-end" } : {}),
119
+ }, children: [backgroundMedia ? _jsxs(View, { pointerEvents: "none", accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: StyleSheet.absoluteFill, children: [backgroundMedia, _jsx(View, { style: [StyleSheet.absoluteFill, { backgroundColor: cardRecipe.backgroundMedia.scrim }] })] }) : null, backgroundInteraction === undefined ? null : _jsx(View, { pointerEvents: "box-none", style: StyleSheet.absoluteFill, children: backgroundInteraction }), mediaBadges === undefined ? null : _jsx(View, { pointerEvents: "box-none", style: { position: "absolute", top: cardRecipe.mediaAction.inset, end: cardRecipe.mediaAction.inset, flexDirection: "row", flexWrap: "wrap", gap: cardRecipe.body.gap, zIndex: 1 }, children: mediaBadges }), _jsxs(CardActivationRegion, { split: split, activation: activationA11y, disabled: disabled, onPress: activate, feedbackOpacity: feedbackOpacity, children: [media === undefined ? null : mediaAction ? _jsxs(Pressable, { accessibilityRole: "button", accessibilityLabel: mediaAction.label, accessibilityState: { disabled }, disabled: disabled, onPress: () => { if (!disabled)
120
+ mediaAction.onActivate(); }, style: ({ pressed }) => [minimumTargetStyle, { opacity: feedbackOpacity(pressed) }], children: [media, mediaAction.icon ? _jsx(View, { pointerEvents: "none", accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: { position: "absolute", end: cardRecipe.mediaAction.inset, bottom: cardRecipe.mediaAction.inset, width: cardRecipe.mediaAction.diameter, height: cardRecipe.mediaAction.diameter, alignItems: "center", justifyContent: "center", borderRadius: tokens.radius.full, backgroundColor: colors.bg, borderWidth: 1, borderColor: colors.border }, children: mediaAction.icon({ color: colors.text, size: cardRecipe.mediaAction.iconSize }) }) : null] }) : _jsx(View, { children: media }), _jsxs(View, { onLayout: ({ nativeEvent: { layout } }) => setHeaderBodyTop(layout.y), style: { gap: cardRecipe.body.gap, padding: bodyPadding, flexGrow: backgroundMedia ? 0 : 1 }, children: [badges === undefined ? null : _jsx(View, { style: { flexDirection: "row", flexWrap: "wrap", gap: cardRecipe.body.gap }, children: badges }), hasHeader ? (_jsxs(View, { onLayout: ({ nativeEvent: { layout } }) => setHeaderRow(current => current?.top === layout.y && current.height === layout.height ? current : { top: layout.y, height: layout.height }), style: {
121
+ alignItems: cardRecipe.header.alignItems,
112
122
  direction: environment.direction,
113
123
  flexDirection: "row",
114
124
  gap: cardRecipe.header.gap,
115
- }, children: [leading === undefined ? null : (_jsx(View, { style: { flexShrink: 0 }, children: leading })), _jsxs(View, { style: { flex: 1, gap: cardRecipe.body.gap, minWidth: 0 }, children: [title === undefined ? null : (_jsx(Text, { accessibilityRole: "header", emphasis: "strong", tone: "primary", variant: "title", children: title })), description === undefined ? null : (_jsx(Text, { emphasis: "regular", tone: "muted", variant: "body", children: description }))] })] })) : null, children === undefined ? null : _jsx(View, { children: children })] })] }), actions === undefined ? null : (_jsx(View, { style: {
125
+ ...(headerActionSize.width > 0 ? { marginEnd: headerActionSize.width + cardRecipe.header.gap, minHeight: headerActionSize.height } : {}),
126
+ }, children: [leading === undefined ? null : (_jsx(View, { style: { flexShrink: 0 }, children: leading })), _jsxs(View, { style: { flex: 1, gap: cardRecipe.body.gap, minWidth: 0 }, children: [title === undefined ? null : (_jsx(Text, { accessibilityRole: "header", emphasis: "strong", tone: "primary", ...(backgroundMedia ? { color: cardRecipe.backgroundMedia.foreground } : {}), variant: "title", children: title })), description === undefined ? null : (_jsx(Text, { emphasis: "regular", tone: "muted", ...(backgroundMedia ? { color: cardRecipe.backgroundMedia.foreground } : {}), variant: "body", children: description }))] })] })) : null, children === undefined ? null : _jsx(View, { style: { flexGrow: 1 }, children: children })] })] }), headerActions === undefined ? null : _jsx(View, { onLayout: ({ nativeEvent: { layout } }) => setHeaderActionSize(current => current.width === layout.width && current.height === layout.height ? current : { width: layout.width, height: layout.height }),
127
+ // Commands stay outside the accessible card target; measured row height also centers wrapped copy.
128
+ style: { position: "absolute", top: headerBodyTop + (headerRow?.top ?? bodyPadding) + Math.max(0, ((headerRow?.height ?? headerActionSize.height) - headerActionSize.height) / 2), end: bodyPadding, flexDirection: "row", alignItems: cardRecipe.header.alignItems, gap: cardRecipe.body.gap, zIndex: 1 }, children: headerActions }), actions === undefined ? null : (_jsx(View, { style: {
116
129
  direction: environment.direction,
117
130
  flexDirection: "row",
118
131
  flexWrap: "wrap",
@@ -130,11 +143,16 @@ export function Card({ children, title, description, leading, media, actions, se
130
143
  function CardActivationRegion({ split, activation, disabled, onPress, feedbackOpacity, children }) {
131
144
  if (!split)
132
145
  return _jsx(_Fragment, { children: children });
133
- return _jsx(Pressable, { ...activation, disabled: disabled, onPress: onPress, style: ({ pressed }) => [minimumTargetStyle, { opacity: feedbackOpacity(pressed) }], children: children });
146
+ return _jsx(Pressable, { ...activation, disabled: disabled, onPress: onPress, style: ({ pressed }) => [minimumTargetStyle, { flexGrow: 1, opacity: feedbackOpacity(pressed) }], children: children });
147
+ }
148
+ /** The quotation and caption stay one visual unit; nested disclosures remain independently accessible. */
149
+ export function QuoteCard({ children, attribution, renderMark, ...props }) {
150
+ const { colors } = useHjmNativeTheme();
151
+ return _jsx(Card, { ...props, leading: _jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: renderMark?.({ color: colors.contentBrand, size: cardRecipe.quotation.markSize }) ?? _jsx(Text, { variant: "heading", tone: "brand", children: "\u201C" }) }), children: _jsxs(View, { style: { gap: cardRecipe.quotation.gap }, children: [children, attribution === undefined ? null : _jsx(Text, { variant: "caption", tone: "muted", children: attribution })] }) });
134
152
  }
135
153
  /**
136
154
  * A List item hands its rows this reporter so the indented separator drawn after the item follows the row's text
137
- * column: leading 40 + gap 12 when the row has a leading frame, the content edge when it has none (2026-10-17 user
155
+ * column: measured leading width + gap when the row has a leading frame, the content edge when it has none (2026-10-17 user
138
156
  * report: a fixed 52 cut the line off midway under rows without leading). Web reads the same fact from the ListRow
139
157
  * root's `data-leading` attribute in CSS.
140
158
  */
@@ -147,12 +165,21 @@ export function ListRow({ title, tone = listRowRecipe.defaults.tone, description
147
165
  // this row's text column (listRecipe.separators). Runs before the loading early return to keep hook order.
148
166
  const reportLeading = useContext(ListItemLeadingContext);
149
167
  const hasLeading = Boolean(leading);
168
+ const [leadingWidth, setLeadingWidth] = useState(listRowRecipe.leadingSize);
169
+ const measureLeading = (event) => {
170
+ if (!reportLeading)
171
+ return;
172
+ const width = event.nativeEvent.layout.width;
173
+ if (Number.isFinite(width) && width >= 0)
174
+ setLeadingWidth(current => current === width ? current : width);
175
+ };
150
176
  useLayoutEffect(() => {
151
177
  if (!reportLeading)
152
178
  return undefined;
153
- reportLeading(hasLeading);
154
- return () => reportLeading(false);
155
- }, [reportLeading, hasLeading]);
179
+ // Ranking rows may compose rank + portrait in a wider public leading slot (2026-10-19).
180
+ reportLeading(hasLeading ? leadingWidth + listRowRecipe.gap : 0);
181
+ return () => reportLeading(0);
182
+ }, [reportLeading, hasLeading, leadingWidth]);
156
183
  const metrics = listRowRecipe.density[density];
157
184
  const interactive = onPress !== undefined;
158
185
  const selected = selectedProp ?? listRowRecipe.defaults.selected;
@@ -197,9 +224,9 @@ export function ListRow({ title, tone = listRowRecipe.defaults.tone, description
197
224
  return _jsxs(View, { testID: props.testID, onLayout: props.onLayout, accessible: Boolean(loadingLabel), accessibilityRole: "progressbar", accessibilityLabel: loadingLabel, accessibilityState: { busy: true }, importantForAccessibility: loadingLabel ? "yes" : "no-hide-descendants", style: [{ alignItems: "center", flexDirection: "row", direction: theme.environment.direction,
198
225
  gap: listRowRecipe.gap, minHeight: visualState.minHeight, marginHorizontal: -metrics.paddingHorizontal,
199
226
  paddingHorizontal: metrics.paddingHorizontal - rowBorder, paddingVertical: metrics.paddingVertical - rowBorder,
200
- borderWidth: rowBorder, borderColor: "transparent" }, layoutStyle], children: [leading ? _jsx(View, { style: [placeholder, leadingFrameStyle] }) : null, _jsxs(View, { style: { flex: 1, minWidth: 0, gap: spacing.xxs }, children: [_jsx(View, { style: [placeholder, { width: `${listRowRecipe.loading.titleWidthPercent}%`, height: theme.tokens.typography[listRowRecipe.title.textVariant].lineHeight }] }), description ? _jsx(View, { style: [placeholder, { width: `${listRowRecipe.loading.descriptionWidthPercent}%`, height: theme.tokens.typography[listRowRecipe.description.textVariant].lineHeight }] }) : null] }), trailing || trailingText ? _jsx(View, { style: [placeholder, { width: listRowRecipe.loading.trailingWidth, height: theme.tokens.typography[listRowRecipe.trailing.textVariant].lineHeight }] }) : null] });
227
+ borderWidth: rowBorder, borderColor: "transparent" }, layoutStyle], children: [leading ? _jsx(View, { onLayout: measureLeading, style: [placeholder, leadingFrameStyle, leadingStyle] }) : null, _jsxs(View, { style: { flex: 1, minWidth: 0, gap: spacing.xxs }, children: [_jsx(View, { style: [placeholder, { width: `${listRowRecipe.loading.titleWidthPercent}%`, height: theme.tokens.typography[listRowRecipe.title.textVariant].lineHeight }] }), description ? _jsx(View, { style: [placeholder, { width: `${listRowRecipe.loading.descriptionWidthPercent}%`, height: theme.tokens.typography[listRowRecipe.description.textVariant].lineHeight }] }) : null] }), trailing || trailingText ? _jsx(View, { style: [placeholder, { width: listRowRecipe.loading.trailingWidth, height: theme.tokens.typography[listRowRecipe.trailing.textVariant].lineHeight }] }) : null] });
201
228
  }
202
- const rowContent = (_jsxs(_Fragment, { children: [leading ? (_jsx(View, { accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", style: [leadingFrameStyle, leadingStyle], children: leading })) : null, _jsxs(View, { style: [{ flex: 1, gap: spacing.xxs, minWidth: 0 }, contentStyle], children: [_jsxs(View, { style: [
229
+ const rowContent = (_jsxs(_Fragment, { children: [leading ? (_jsx(View, { onLayout: measureLeading, accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", style: [leadingFrameStyle, leadingStyle], children: leading })) : null, _jsxs(View, { style: [{ flex: 1, gap: spacing.xxs, minWidth: 0 }, contentStyle], children: [_jsxs(View, { style: [
203
230
  {
204
231
  alignItems: "center",
205
232
  direction: theme.environment.direction,
@@ -639,21 +666,28 @@ export function List({ label, children, separator = listRecipe.defaults.separato
639
666
  layoutStyle,
640
667
  ], children: items.map((item, index) => (_jsx(ListItem, { borderColor: colors.border, separator: index < items.length - 1 ? separatorContract : null, children: item }, isValidElement(item) && item.key !== null ? item.key : `hjm-list-${index}`))) }));
641
668
  }
669
+ /** Decorative separator for a product-owned virtual collection; never replaces its accessible row. */
670
+ export function ListSeparator({ separator = "content", leading = false, layoutStyle }) {
671
+ const { colors } = useHjmNativeTheme();
672
+ const insets = listRecipe.separators[separator];
673
+ return insets ? _jsx(ListSeparatorFrame, { color: colors.border, start: leading ? insets.leadingInsetStart : insets.insetStart, end: insets.insetEnd, layoutStyle: layoutStyle }) : null;
674
+ }
675
+ // List and virtual hosts share the actual line. List keeps its measured leading width for custom row slots.
676
+ function ListSeparatorFrame({ color, start, end, layoutStyle }) {
677
+ // Keep host placement outside the line: Yoga's explicit logical marginStart/End would otherwise override
678
+ // a caller's marginHorizontal even when the content-edge inset is zero.
679
+ return _jsx(View, { accessible: false, importantForAccessibility: "no", style: layoutStyle, children: _jsx(View, { accessible: false, importantForAccessibility: "no", style: { backgroundColor: color, height: 1, marginStart: start, marginEnd: end } }) });
680
+ }
642
681
  /** One list item and the separator that belongs to it (drawn after it, as an iOS cell separator). */
643
682
  function ListItem({ borderColor, children, separator, }) {
644
- const [hasLeading, setHasLeading] = useState(false);
645
- return (_jsxs(View, { children: [_jsx(ListItemLeadingContext.Provider, { value: setHasLeading, children: children }), separator ? (_jsx(View, { accessible: false, style: {
646
- backgroundColor: borderColor,
647
- height: 1,
648
- marginEnd: separator.insetEnd,
649
- marginStart: hasLeading ? separator.leadingInsetStart : separator.insetStart,
650
- } })) : null] }));
683
+ const [contentInset, setContentInset] = useState(0);
684
+ return (_jsxs(View, { children: [_jsx(ListItemLeadingContext.Provider, { value: setContentInset, children: children }), separator ? _jsx(ListSeparatorFrame, { color: borderColor, start: separator.leadingInsetStart === separator.insetStart ? separator.insetStart : contentInset, end: separator.insetEnd }) : null] }));
651
685
  }
652
686
  export function Statistic(props) {
653
687
  return renderStatistic(props);
654
688
  }
655
689
  // StatisticGroup reuses this renderer with its calculated layout width.
656
- function renderStatistic({ descriptor, density = "comfortable", presentation = "plain", contextLabel, accessibilityLabel, composeAccessibilityLabel, renderTrendMark, layoutStyle, }) {
690
+ function renderStatistic({ descriptor, density = "comfortable", presentation = "plain", contextLabel, accessibilityLabel, composeAccessibilityLabel, leading, valueColor, renderTrendMark, layoutStyle, }, bar = false, barDivider = false) {
657
691
  const resolved = resolveStatisticDescriptor(descriptor);
658
692
  const theme = useHjmNativeTheme();
659
693
  const densityContract = statisticRecipe.density[density];
@@ -678,6 +712,13 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
678
712
  const trendColor = resolved.trend
679
713
  ? resolveColorReference(statisticRecipe.trend.tones[resolved.trend.tone], theme.palette)
680
714
  : undefined;
715
+ const labelNode = (_jsx(Text, { accessible: false, style: [
716
+ {
717
+ color: resolveColorReference(statisticRecipe.label.color, theme.palette),
718
+ fontWeight: statisticRecipe.label.fontWeight,
719
+ ...(bar ? { textAlign: "center" } : {}),
720
+ },
721
+ ], variant: densityContract.labelVariant, children: resolved.label }));
681
722
  return (_jsxs(View, { accessibilityLabel: announcement, accessible: true, style: [
682
723
  {
683
724
  backgroundColor: presentationContract.background
@@ -686,34 +727,31 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
686
727
  borderColor: presentationContract.border
687
728
  ? resolveColorReference(presentationContract.border, theme.palette)
688
729
  : "transparent",
689
- borderRadius: theme.tokens.radius[presentationContract.radius],
730
+ borderRadius: bar ? 0 : theme.tokens.radius[presentationContract.radius],
690
731
  borderWidth: presentationContract.borderWidth,
691
- gap: densityContract.gap,
732
+ gap: bar ? statisticRecipe.group.bar.valueGap : densityContract.gap,
733
+ ...(bar ? { alignItems: "center", paddingHorizontal: statisticRecipe.group.bar.cellPadding, borderStartWidth: barDivider ? 1 : 0, borderStartColor: theme.colors.border } : {}),
692
734
  minWidth: 0,
693
735
  // Plain statistics align with surrounding text; only the surface plate is inset (Web keys on data-presentation).
694
736
  padding: presentation === "surface" ? densityContract.padding : 0,
695
737
  },
696
738
  layoutStyle,
697
- ], children: [_jsx(Text, { accessible: false, style: [
698
- {
699
- color: resolveColorReference(statisticRecipe.label.color, theme.palette),
700
- fontWeight: statisticRecipe.label.fontWeight,
701
- },
702
- ], variant: densityContract.labelVariant, children: resolved.label }), _jsxs(View, { accessible: false, style: {
703
- alignItems: "baseline",
739
+ ], children: [!bar && labelNode, _jsxs(View, { accessible: false, style: {
740
+ alignItems: leading ? "center" : "baseline",
741
+ ...(bar ? { justifyContent: "center" } : {}),
704
742
  direction: theme.environment.direction,
705
743
  flexDirection: "row",
706
744
  flexWrap: "wrap",
707
745
  gap: spacing.xxs,
708
746
  minWidth: 0,
709
- }, children: [resolved.prefix ? (_jsx(Text, { accessible: false, style: [
747
+ }, children: [leading === undefined ? null : _jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: leading }), resolved.prefix ? (_jsx(Text, { accessible: false, style: [
710
748
  {
711
749
  color: resolveColorReference(statisticRecipe.affix.color, theme.palette),
712
750
  fontWeight: statisticRecipe.affix.fontWeight,
713
751
  },
714
752
  ], variant: statisticRecipe.affix.textVariant, children: resolved.prefix })) : null, _jsx(Text, { accessible: false, style: [
715
753
  {
716
- color: resolveColorReference(statisticRecipe.value.color, theme.palette),
754
+ color: valueColor ?? resolveColorReference(statisticRecipe.value.color, theme.palette),
717
755
  flexShrink: 1,
718
756
  fontVariant: ["tabular-nums"],
719
757
  fontWeight: statisticRecipe.value.fontWeight,
@@ -723,7 +761,7 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
723
761
  color: resolveColorReference(statisticRecipe.affix.color, theme.palette),
724
762
  fontWeight: statisticRecipe.affix.fontWeight,
725
763
  },
726
- ], variant: statisticRecipe.affix.textVariant, children: resolved.suffix })) : null] }), resolved.trend ? (_jsxs(View, { accessible: false, style: {
764
+ ], variant: statisticRecipe.affix.textVariant, children: resolved.suffix })) : null] }), bar && labelNode, resolved.trend ? (_jsxs(View, { accessible: false, style: {
727
765
  alignItems: "center",
728
766
  flexDirection: "row",
729
767
  flexWrap: "wrap",
@@ -739,11 +777,11 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
739
777
  { color: resolveColorReference(statisticRecipe.hint.color, theme.palette) },
740
778
  ], variant: statisticRecipe.hint.textVariant, children: resolved.hint })) : null] }));
741
779
  }
742
- export function StatisticGroup({ label, descriptor, availableWidth, density, presentation, composeAccessibilityLabel, renderTrendMark, layoutStyle, onLayout, ...props }) {
780
+ export function StatisticGroup({ label, descriptor, availableWidth, density, presentation, composeAccessibilityLabel, arrangement = "grid", renderLeading, getValueColor, renderTrendMark, layoutStyle, onLayout, ...props }) {
743
781
  assertNoRemovedStyleProps("StatisticGroup", props, ["style", "itemStyle"]);
744
782
  validateStatisticGroup(descriptor);
745
783
  const { width: windowWidth } = useWindowDimensions();
746
- const { environment } = useHjmNativeTheme();
784
+ const { environment, colors } = useHjmNativeTheme();
747
785
  const [measuredWidth, setMeasuredWidth] = useState(null);
748
786
  const innerWidth = availableWidth ?? measuredWidth ?? windowWidth;
749
787
  if (!Number.isFinite(innerWidth) || innerWidth <= 0) {
@@ -751,18 +789,19 @@ export function StatisticGroup({ label, descriptor, availableWidth, density, pre
751
789
  }
752
790
  const requested = descriptor.columns ?? statisticRecipe.defaults.columns;
753
791
  const minItemWidth = statisticRecipe.group.minItemWidth * Math.max(1, environment.textScale);
754
- let columns = requested;
755
- while (columns > 1 &&
756
- (innerWidth - statisticRecipe.group.gap * (columns - 1)) / columns < minItemWidth) {
792
+ let columns = arrangement === "bar" ? descriptor.items.length : requested;
793
+ const gap = arrangement === "bar" ? 0 : statisticRecipe.group.gap;
794
+ while (arrangement !== "bar" && columns > 1 &&
795
+ (innerWidth - gap * (columns - 1)) / columns < minItemWidth) {
757
796
  columns -= 1;
758
797
  }
759
- const itemWidth = (innerWidth - statisticRecipe.group.gap * (columns - 1)) / columns;
798
+ const itemWidth = (innerWidth - gap * (columns - 1)) / columns;
760
799
  const remainder = descriptor.items.length % columns;
761
800
  const finalRowCount = remainder === 0 ? columns : remainder;
762
801
  const finalRowStart = descriptor.items.length - finalRowCount;
763
802
  const finalRowItemWidth = finalRowCount === columns
764
803
  ? itemWidth
765
- : (innerWidth - statisticRecipe.group.gap * (finalRowCount - 1)) / finalRowCount;
804
+ : (innerWidth - gap * (finalRowCount - 1)) / finalRowCount;
766
805
  const handleLayout = (event) => {
767
806
  onLayout?.(event);
768
807
  if (availableWidth !== undefined)
@@ -777,63 +816,65 @@ export function StatisticGroup({ label, descriptor, availableWidth, density, pre
777
816
  direction: environment.direction,
778
817
  flexDirection: "row",
779
818
  flexWrap: "wrap",
780
- gap: statisticRecipe.group.gap,
819
+ gap,
781
820
  },
782
821
  layoutStyle,
783
- ], children: descriptor.items.map((item, index) => (_jsx(StatisticGroupItem, { contextLabel: label, descriptor: item, ...(composeAccessibilityLabel === undefined ? {} : { composeAccessibilityLabel }), ...(density === undefined ? {} : { density }), ...(presentation === undefined ? {} : { presentation }), ...(renderTrendMark === undefined ? {} : { renderTrendMark }), layoutStyle: { width: index >= finalRowStart ? finalRowItemWidth : itemWidth } }, item.id))) }));
822
+ ], children: descriptor.items.map((item, index) => {
823
+ const valueColor = getValueColor?.(item);
824
+ return (_jsx(StatisticGroupItem, { bar: arrangement === "bar", barDivider: index > 0, ...(valueColor ? { valueColor } : {}), ...(renderLeading ? { leading: renderLeading(item, { color: valueColor ?? colors.text, size: statisticRecipe.group.bar.iconSize }) } : {}), contextLabel: label, descriptor: item, ...(composeAccessibilityLabel === undefined ? {} : { composeAccessibilityLabel }), ...(density === undefined ? {} : { density }), ...(presentation === undefined ? {} : { presentation }), ...(renderTrendMark === undefined ? {} : { renderTrendMark }), layoutStyle: { width: index >= finalRowStart ? finalRowItemWidth : itemWidth } }, item.id));
825
+ }) }));
784
826
  }
785
827
  /** Group cell: same render as Statistic without attributing the group's styles to the caller. */
786
- function StatisticGroupItem(props) {
787
- return renderStatistic(props);
828
+ function StatisticGroupItem({ bar, barDivider, ...props }) {
829
+ return renderStatistic(props, bar, barDivider);
788
830
  }
789
831
  /** Ordered record of completed events; unlike Steps it has no current cursor. */
790
- export function Timeline({ items, composeAccessibleName, layoutStyle, ...props }) {
832
+ export function Timeline({ items, composeAccessibleName, renderMetadata, renderActions, renderList, layoutStyle, ...props }) {
791
833
  assertNoRemovedStyleProps("Timeline", props, ["style"]);
792
834
  const theme = useHjmNativeTheme();
793
835
  const resolved = resolveTimelineDescriptor({ items }, { composeAccessibleName });
794
836
  // Dot, label first line and timestamp share the label's rendered first line box (token × text scale), matching
795
837
  // Web's 1lh anchor (2026-10-17 measured audit: the dot sat at the top and the caption rode the baseline).
796
838
  const labelLineHeight = theme.tokens.typography[timelineRecipe.label.textVariant].lineHeight * theme.textScaling.scale;
797
- const timestampLineHeight = theme.tokens.typography[timelineRecipe.timestamp.textVariant].lineHeight * theme.textScaling.scale;
798
- return (_jsx(View, { ...props, style: [{ gap: timelineRecipe.gap }, layoutStyle], children: resolved.map((item, index) => {
799
- const tone = timelineRecipe.dot.tones[item.tone];
800
- const accessibilityLabel = [
801
- item.accessibleName,
802
- item.timestamp,
803
- item.description,
804
- ]
805
- .filter(Boolean)
806
- .join(", ");
807
- return (_jsxs(View, { accessible: true, accessibilityLabel: accessibilityLabel, style: { flexDirection: "row", gap: spacing.sm }, children: [_jsxs(View, { importantForAccessibility: "no-hide-descendants", style: { alignItems: "center", width: 16 }, children: [_jsx(View, { style: {
808
- backgroundColor: resolveColorReference(tone.fill, theme.palette),
809
- borderColor: tone.border
810
- ? resolveColorReference(tone.border, theme.palette)
811
- : "transparent",
812
- borderRadius: radius.full,
813
- borderWidth: tone.border
814
- ? timelineRecipe.dot.borderWidth
815
- : 0,
816
- height: timelineRecipe.dot.diameter,
817
- marginTop: (labelLineHeight - timelineRecipe.dot.diameter) / 2,
818
- width: timelineRecipe.dot.diameter,
819
- } }), index < resolved.length - 1 ? (_jsx(View, { style: {
820
- backgroundColor: resolveColorReference(timelineRecipe.connector.tone, theme.palette),
821
- flex: 1,
822
- width: timelineRecipe.connector.width,
823
- } })) : null] }), _jsxs(View, { importantForAccessibility: "no-hide-descendants", style: { flex: 1, gap: spacing.xxs, minWidth: 0, paddingBottom: spacing.xxs }, children: [_jsxs(View, { style: {
824
- alignItems: "flex-start",
825
- flexDirection: "row",
826
- flexWrap: "wrap",
827
- gap: spacing.xs,
828
- justifyContent: "space-between",
829
- }, children: [_jsx(Text, { emphasis: "medium", style: {
830
- color: resolveColorReference(timelineRecipe.label.color, theme.palette),
831
- }, variant: timelineRecipe.label.textVariant, children: item.label }), item.timestamp ? (_jsx(Text, { style: {
832
- color: resolveColorReference(timelineRecipe.timestamp.color, theme.palette),
833
- marginTop: (labelLineHeight - timestampLineHeight) / 2,
834
- }, variant: timelineRecipe.timestamp.textVariant, children: item.timestamp })) : null] }), item.description ? (_jsx(Text, { style: {
835
- color: resolveColorReference(timelineRecipe.description.color, theme.palette),
836
- }, variant: timelineRecipe.description.textVariant, children: item.description })) : null] })] }, item.id));
837
- }) }));
839
+ const renderRecord = (item, index) => {
840
+ const actions = renderActions?.(item);
841
+ const tone = timelineRecipe.dot.tones[item.tone];
842
+ const accessibilityLabel = [
843
+ item.accessibleName,
844
+ item.description,
845
+ item.timestamp,
846
+ ]
847
+ .filter(Boolean)
848
+ .join(", ");
849
+ return (_jsxs(View, { accessible: !actions, accessibilityLabel: actions ? undefined : accessibilityLabel, style: { flexDirection: "row", gap: spacing.sm, padding: timelineRecipe.item.padding, borderRadius: radius.md, backgroundColor: item.emphasized ? resolveColorReference(timelineRecipe.item.emphasisBackground, theme.palette) : undefined }, children: [_jsxs(View, { importantForAccessibility: "no-hide-descendants", style: { alignItems: "center", width: 16 }, children: [_jsx(View, { style: {
850
+ backgroundColor: resolveColorReference(tone.fill, theme.palette),
851
+ borderColor: tone.border
852
+ ? resolveColorReference(tone.border, theme.palette)
853
+ : "transparent",
854
+ borderRadius: radius.full,
855
+ borderWidth: tone.border
856
+ ? timelineRecipe.dot.borderWidth
857
+ : 0,
858
+ height: timelineRecipe.dot.diameter,
859
+ marginTop: (labelLineHeight - timelineRecipe.dot.diameter) / 2,
860
+ width: timelineRecipe.dot.diameter,
861
+ } }), index < resolved.length - 1 ? (_jsx(View, { style: {
862
+ backgroundColor: resolveColorReference(timelineRecipe.connector.tone, theme.palette),
863
+ position: "absolute",
864
+ top: (labelLineHeight + timelineRecipe.dot.diameter) / 2,
865
+ bottom: -timelineRecipe.gap - 2 * timelineRecipe.item.padding - labelLineHeight / 2,
866
+ width: timelineRecipe.connector.width,
867
+ } })) : null] }), _jsxs(View, { accessible: !!actions, accessibilityLabel: actions ? accessibilityLabel : undefined, importantForAccessibility: actions ? "auto" : "no-hide-descendants", style: { flex: 1, gap: spacing.xxs, minWidth: 0, paddingBottom: spacing.xxs }, children: [_jsxs(View, { style: {
868
+ alignItems: "flex-start",
869
+ flexDirection: "row",
870
+ flexWrap: "wrap",
871
+ gap: spacing.xs,
872
+ }, children: [_jsx(Text, { emphasis: "medium", style: {
873
+ color: resolveColorReference(timelineRecipe.label.color, theme.palette),
874
+ }, variant: timelineRecipe.label.textVariant, children: item.label }), renderMetadata?.(item)] }), item.description ? (_jsx(Text, { style: {
875
+ color: resolveColorReference(timelineRecipe.description.color, theme.palette),
876
+ }, variant: timelineRecipe.description.textVariant, children: item.description })) : null, item.timestamp ? _jsx(Text, { tone: "muted", variant: timelineRecipe.timestamp.textVariant, children: item.timestamp }) : null] }), actions ? _jsx(View, { style: { flexDirection: "row", alignSelf: "center", alignItems: "center", gap: spacing.xs }, children: actions }) : null] }, item.id));
877
+ };
878
+ return _jsx(View, { ...props, style: [renderList ? {} : { gap: timelineRecipe.gap }, layoutStyle], children: renderList ? renderList({ items: resolved, renderItem: renderRecord, separator: _jsx(View, { style: { height: timelineRecipe.gap } }) }) : resolved.map(renderRecord) });
838
879
  }
839
880
  //# sourceMappingURL=data-display.js.map