@hjmds/react-native 1.17.2 → 1.19.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 (203) hide show
  1. package/README.md +8 -8
  2. package/dist/actions.d.ts +3 -23
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +8 -11
  5. package/dist/actions.js.map +1 -1
  6. package/dist/activity-chip.d.ts +29 -0
  7. package/dist/activity-chip.d.ts.map +1 -0
  8. package/dist/activity-chip.js +54 -0
  9. package/dist/activity-chip.js.map +1 -0
  10. package/dist/agreement.d.ts +1 -7
  11. package/dist/agreement.d.ts.map +1 -1
  12. package/dist/agreement.js +21 -15
  13. package/dist/agreement.js.map +1 -1
  14. package/dist/asset.d.ts +2 -13
  15. package/dist/asset.d.ts.map +1 -1
  16. package/dist/asset.js +4 -7
  17. package/dist/asset.js.map +1 -1
  18. package/dist/bottom-info.d.ts +1 -7
  19. package/dist/bottom-info.d.ts.map +1 -1
  20. package/dist/bottom-info.js +2 -4
  21. package/dist/bottom-info.js.map +1 -1
  22. package/dist/carousel-motion.d.ts +1 -0
  23. package/dist/carousel-motion.d.ts.map +1 -1
  24. package/dist/carousel-motion.js +5 -3
  25. package/dist/carousel-motion.js.map +1 -1
  26. package/dist/carousel.d.ts +1 -7
  27. package/dist/carousel.d.ts.map +1 -1
  28. package/dist/carousel.js +14 -6
  29. package/dist/carousel.js.map +1 -1
  30. package/dist/collapsible.d.ts +1 -7
  31. package/dist/collapsible.d.ts.map +1 -1
  32. package/dist/collapsible.js +4 -4
  33. package/dist/collapsible.js.map +1 -1
  34. package/dist/content-transition.d.ts +2 -1
  35. package/dist/content-transition.d.ts.map +1 -1
  36. package/dist/content-transition.js +3 -3
  37. package/dist/content-transition.js.map +1 -1
  38. package/dist/data-display.d.ts +23 -154
  39. package/dist/data-display.d.ts.map +1 -1
  40. package/dist/data-display.js +86 -92
  41. package/dist/data-display.js.map +1 -1
  42. package/dist/date-entry.d.ts +1 -0
  43. package/dist/date-entry.d.ts.map +1 -1
  44. package/dist/date-entry.js +22 -20
  45. package/dist/date-entry.js.map +1 -1
  46. package/dist/date-picker.d.ts +1 -7
  47. package/dist/date-picker.d.ts.map +1 -1
  48. package/dist/date-picker.js +19 -11
  49. package/dist/date-picker.js.map +1 -1
  50. package/dist/duration-field.d.ts +1 -1
  51. package/dist/duration-field.d.ts.map +1 -1
  52. package/dist/duration-field.js +11 -9
  53. package/dist/duration-field.js.map +1 -1
  54. package/dist/evidence.d.ts +1 -1
  55. package/dist/evidence.js +1 -1
  56. package/dist/feedback.d.ts +9 -88
  57. package/dist/feedback.d.ts.map +1 -1
  58. package/dist/feedback.js +124 -81
  59. package/dist/feedback.js.map +1 -1
  60. package/dist/field-group.d.ts +3 -2
  61. package/dist/field-group.d.ts.map +1 -1
  62. package/dist/field-group.js +7 -4
  63. package/dist/field-group.js.map +1 -1
  64. package/dist/file-picker.d.ts +1 -7
  65. package/dist/file-picker.d.ts.map +1 -1
  66. package/dist/file-picker.js +21 -11
  67. package/dist/file-picker.js.map +1 -1
  68. package/dist/forms.d.ts +6 -21
  69. package/dist/forms.d.ts.map +1 -1
  70. package/dist/forms.js +29 -35
  71. package/dist/forms.js.map +1 -1
  72. package/dist/gravity-letters.d.ts.map +1 -1
  73. package/dist/gravity-letters.js +13 -5
  74. package/dist/gravity-letters.js.map +1 -1
  75. package/dist/grid-reveal.d.ts.map +1 -1
  76. package/dist/grid-reveal.js +10 -2
  77. package/dist/grid-reveal.js.map +1 -1
  78. package/dist/heading.d.ts +1 -7
  79. package/dist/heading.d.ts.map +1 -1
  80. package/dist/heading.js +1 -4
  81. package/dist/heading.js.map +1 -1
  82. package/dist/image-viewer.d.ts.map +1 -1
  83. package/dist/image-viewer.js +2 -1
  84. package/dist/image-viewer.js.map +1 -1
  85. package/dist/index.d.ts +1 -0
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/inline-confirm.d.ts.map +1 -1
  90. package/dist/inline-confirm.js +5 -1
  91. package/dist/inline-confirm.js.map +1 -1
  92. package/dist/inputs.d.ts +4 -71
  93. package/dist/inputs.d.ts.map +1 -1
  94. package/dist/inputs.js +52 -67
  95. package/dist/inputs.js.map +1 -1
  96. package/dist/internal/accessible-focus.d.ts +3 -0
  97. package/dist/internal/accessible-focus.d.ts.map +1 -0
  98. package/dist/internal/accessible-focus.js +15 -0
  99. package/dist/internal/accessible-focus.js.map +1 -0
  100. package/dist/internal/diagnostics.d.ts +7 -0
  101. package/dist/internal/diagnostics.d.ts.map +1 -0
  102. package/dist/internal/diagnostics.js +20 -0
  103. package/dist/internal/diagnostics.js.map +1 -0
  104. package/dist/internal/document-resource.d.ts.map +1 -1
  105. package/dist/internal/document-resource.js +2 -2
  106. package/dist/internal/document-resource.js.map +1 -1
  107. package/dist/internal/recipe-button.js +1 -1
  108. package/dist/internal/recipe-button.js.map +1 -1
  109. package/dist/internal/spinner.d.ts +1 -7
  110. package/dist/internal/spinner.d.ts.map +1 -1
  111. package/dist/internal/spinner.js +2 -4
  112. package/dist/internal/spinner.js.map +1 -1
  113. package/dist/masonry.d.ts.map +1 -1
  114. package/dist/masonry.js +2 -1
  115. package/dist/masonry.js.map +1 -1
  116. package/dist/mentions.d.ts +1 -7
  117. package/dist/mentions.d.ts.map +1 -1
  118. package/dist/mentions.js +11 -7
  119. package/dist/mentions.js.map +1 -1
  120. package/dist/navigation.d.ts +4 -74
  121. package/dist/navigation.d.ts.map +1 -1
  122. package/dist/navigation.js +86 -45
  123. package/dist/navigation.js.map +1 -1
  124. package/dist/number-field.d.ts +1 -21
  125. package/dist/number-field.d.ts.map +1 -1
  126. package/dist/number-field.js +6 -5
  127. package/dist/number-field.js.map +1 -1
  128. package/dist/overlays.d.ts +7 -16
  129. package/dist/overlays.d.ts.map +1 -1
  130. package/dist/overlays.js +220 -213
  131. package/dist/overlays.js.map +1 -1
  132. package/dist/primitives.d.ts +3 -18
  133. package/dist/primitives.d.ts.map +1 -1
  134. package/dist/primitives.js +8 -10
  135. package/dist/primitives.js.map +1 -1
  136. package/dist/provider-button.d.ts +1 -7
  137. package/dist/provider-button.d.ts.map +1 -1
  138. package/dist/provider-button.js +1 -4
  139. package/dist/provider-button.js.map +1 -1
  140. package/dist/provider.d.ts.map +1 -1
  141. package/dist/provider.js +9 -1
  142. package/dist/provider.js.map +1 -1
  143. package/dist/saved-items.d.ts.map +1 -1
  144. package/dist/saved-items.js +6 -1
  145. package/dist/saved-items.js.map +1 -1
  146. package/dist/screen-flows.d.ts +1 -2
  147. package/dist/screen-flows.d.ts.map +1 -1
  148. package/dist/screen-flows.js +60 -16
  149. package/dist/screen-flows.js.map +1 -1
  150. package/dist/screens.d.ts +1 -1
  151. package/dist/screens.d.ts.map +1 -1
  152. package/dist/screens.js +32 -15
  153. package/dist/screens.js.map +1 -1
  154. package/dist/sheet-gesture.d.ts.map +1 -1
  155. package/dist/sheet-gesture.js +6 -3
  156. package/dist/sheet-gesture.js.map +1 -1
  157. package/dist/slider.d.ts +1 -21
  158. package/dist/slider.d.ts.map +1 -1
  159. package/dist/slider.js +3 -5
  160. package/dist/slider.js.map +1 -1
  161. package/dist/sortable.d.ts.map +1 -1
  162. package/dist/sortable.js +2 -1
  163. package/dist/sortable.js.map +1 -1
  164. package/dist/status-text.d.ts +17 -0
  165. package/dist/status-text.d.ts.map +1 -0
  166. package/dist/status-text.js +18 -0
  167. package/dist/status-text.js.map +1 -0
  168. package/dist/steps.d.ts +1 -7
  169. package/dist/steps.d.ts.map +1 -1
  170. package/dist/steps.js +2 -4
  171. package/dist/steps.js.map +1 -1
  172. package/dist/swipe-actions.d.ts.map +1 -1
  173. package/dist/swipe-actions.js +13 -2
  174. package/dist/swipe-actions.js.map +1 -1
  175. package/dist/tags-input.d.ts +1 -7
  176. package/dist/tags-input.d.ts.map +1 -1
  177. package/dist/tags-input.js +2 -4
  178. package/dist/tags-input.js.map +1 -1
  179. package/dist/toggle-group.d.ts +1 -7
  180. package/dist/toggle-group.d.ts.map +1 -1
  181. package/dist/toggle-group.js +10 -5
  182. package/dist/toggle-group.js.map +1 -1
  183. package/dist/top.d.ts +1 -7
  184. package/dist/top.d.ts.map +1 -1
  185. package/dist/top.js +1 -4
  186. package/dist/top.js.map +1 -1
  187. package/dist/transfer-list.d.ts +2 -8
  188. package/dist/transfer-list.d.ts.map +1 -1
  189. package/dist/transfer-list.js +30 -11
  190. package/dist/transfer-list.js.map +1 -1
  191. package/dist/upload-item.d.ts +1 -7
  192. package/dist/upload-item.d.ts.map +1 -1
  193. package/dist/upload-item.js +2 -4
  194. package/dist/upload-item.js.map +1 -1
  195. package/dist/virtual-list.d.ts.map +1 -1
  196. package/dist/virtual-list.js +2 -1
  197. package/dist/virtual-list.js.map +1 -1
  198. package/docs/liquid-toast.md +20 -0
  199. package/package.json +17 -4
  200. package/dist/internal/deprecated-style.d.ts +0 -8
  201. package/dist/internal/deprecated-style.d.ts.map +0 -1
  202. package/dist/internal/deprecated-style.js +0 -34
  203. package/dist/internal/deprecated-style.js.map +0 -1
@@ -1,25 +1,25 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { assertNoRemovedStyleProps } from "./internal/diagnostics.js";
2
3
  import { resolveAvatarInitials } from "@hjmds/design-contracts/avatar-fallback";
3
4
  import { resolveColorReference } from "@hjmds/design-contracts/color-references";
4
5
  import { fontWeight, glyph, radius, spacing } from "@hjmds/design-contracts/foundations";
5
6
  import { resolveDescriptionListColumnCount, resolveDescriptionListDescriptor, } from "@hjmds/design-contracts/components/description-list";
6
7
  import { resolveStatisticDescriptor, validateStatisticGroup, } from "@hjmds/design-contracts/components/statistic";
7
8
  import { resolveTagDescriptor, resolveTagPresentation, tagRecipe, } from "@hjmds/design-contracts/components/tag";
8
- import { warnDeprecatedStyleProps } from "./internal/deprecated-style.js";
9
9
  import { cardRecipe } from "@hjmds/design-contracts/components/card";
10
10
  import { imageRecipe, nativeResizeModes, resolveImageAspectRatio, resolveImageDescriptor, resolveImageFallbackAccessibilityLabel, } from "@hjmds/design-contracts/components/image";
11
11
  import { resolveTimelineDescriptor, timelineRecipe, } from "@hjmds/design-contracts/components/timeline";
12
12
  import { surfaceDefaults, surfaceGeometry } from "@hjmds/design-contracts/recipes/base";
13
13
  import { accordionRecipe, counterBadgeRecipe, badgeRecipe, listRecipe, formatCounterBadgeCount, listRowRecipe, statisticRecipe, } from "@hjmds/design-contracts/recipes";
14
- import { Children, isValidElement, useEffect, useMemo, useRef, useState, } from "react";
14
+ import { Children, isValidElement, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
15
15
  import { Image as NativeImage, LayoutAnimation, Pressable, StyleSheet, View, useWindowDimensions, } from "react-native";
16
16
  import { useControllableState } from "./internal/state.js";
17
17
  import { minimumTargetStyle } from "./internal/styles.js";
18
18
  import { webDisclosureProps, webOnly } from "./internal/web-a11y.js";
19
19
  import { Surface, Text, } from "./primitives.js";
20
20
  import { useHjmNativeTheme } from "./provider.js";
21
- export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRecipe.defaults.size, variant = badgeRecipe.defaults.variant, leading, accessibilityLabel, style, labelStyle, layoutStyle, ...props }) {
22
- warnDeprecatedStyleProps("Badge", { style, labelStyle }, "layoutStyle for placement and tone/size/variant for appearance");
21
+ export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRecipe.defaults.size, variant = badgeRecipe.defaults.variant, leading, accessibilityLabel, layoutStyle, ...props }) {
22
+ assertNoRemovedStyleProps("Badge", props, ["style", "labelStyle"]);
23
23
  const theme = useHjmNativeTheme();
24
24
  const presentation = badgeRecipe.tones[tone];
25
25
  const metrics = badgeRecipe.sizes[size];
@@ -49,17 +49,15 @@ export function Badge({ label, tone = badgeRecipe.defaults.tone, size = badgeRec
49
49
  minHeight: metrics.minHeight,
50
50
  paddingHorizontal: metrics.paddingHorizontal,
51
51
  },
52
- style,
53
52
  layoutStyle,
54
53
  ], 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: [
55
54
  {
56
55
  color: resolveColorReference(outlined ? presentation.outlineContent : presentation.content, theme.palette),
57
56
  },
58
- labelStyle,
59
57
  ], variant: metrics.textVariant, children: label })] }));
60
58
  }
61
- export function Tag({ children, tone, accessibilityLabel, layoutStyle, style, labelStyle, ...props }) {
62
- warnDeprecatedStyleProps("Tag", { style, labelStyle }, "layoutStyle for placement and tone for appearance");
59
+ export function Tag({ children, tone, accessibilityLabel, layoutStyle, ...props }) {
60
+ assertNoRemovedStyleProps("Tag", props, ["style", "labelStyle"]);
63
61
  const theme = useHjmNativeTheme();
64
62
  const resolvedLabel = children;
65
63
  if (resolvedLabel === undefined) {
@@ -84,15 +82,17 @@ export function Tag({ children, tone, accessibilityLabel, layoutStyle, style, la
84
82
  minHeight: tagRecipe.size.minHeight,
85
83
  paddingHorizontal: tagRecipe.size.paddingHorizontal,
86
84
  },
87
- style,
88
85
  layoutStyle,
89
- ], children: _jsx(Text, { align: "center", emphasis: "medium", style: [{ color: presentation.content }, labelStyle], variant: tagRecipe.size.textVariant, children: descriptor.label }) }));
86
+ ], children: _jsx(Text, { align: "center", emphasis: "medium", style: [{ color: presentation.content }], variant: tagRecipe.size.textVariant, children: descriptor.label }) }));
90
87
  }
91
- export function Card({ children, title, description, leading, media, actions, selected = cardRecipe.defaults.selected, tone = cardRecipe.defaults.tone, bordered = cardRecipe.defaults.bordered, padding = cardRecipe.defaults.padding, layoutStyle, radius: cornerRadius = surfaceDefaults.radius, ...props }) {
88
+ 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 }) {
92
89
  const { environment, tokens } = useHjmNativeTheme();
90
+ if (onActivate && (!accessibilityLabel?.trim() || actions !== undefined)) {
91
+ throw new TypeError("Interactive Card requires accessibilityLabel and no actions");
92
+ }
93
93
  const bodyPadding = surfaceGeometry.paddings[padding];
94
94
  const hasHeader = leading !== undefined || title !== undefined || description !== undefined;
95
- return (_jsx(Surface, { ...props, bordered: bordered, padding: "none", radius: cornerRadius, ...(layoutStyle === undefined ? {} : { layoutStyle }), tone: selected ? cardRecipe.selectedTone : tone, children: _jsxs(View, { style: {
95
+ const frame = (_jsx(Surface, { ...props, bordered: bordered, padding: "none", radius: cornerRadius, ...(onActivate ? {} : { accessibilityLabel, accessibilityHint }), ...(layoutStyle === undefined || onActivate ? {} : { layoutStyle }), tone: selected ? cardRecipe.selectedTone : tone, children: _jsxs(View, { style: {
96
96
  overflow: "hidden",
97
97
  borderRadius: tokens.radius[cornerRadius],
98
98
  }, children: [media === undefined ? null : _jsx(View, { children: media }), _jsxs(View, { style: { gap: cardRecipe.body.gap, padding: bodyPadding }, children: [hasHeader ? (_jsxs(View, { style: {
@@ -108,10 +108,18 @@ export function Card({ children, title, description, leading, media, actions, se
108
108
  paddingBottom: cardRecipe.actions.paddingBottom,
109
109
  paddingHorizontal: cardRecipe.actions.paddingHorizontal,
110
110
  }, children: actions }))] }) }));
111
+ if (!onActivate)
112
+ return frame;
113
+ // Keep Surface's material/clip inside one native action host. App-owned wrappers
114
+ // previously had to reinvent disabled/selected naming and press feedback.
115
+ return _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: accessibilityLabel, accessibilityHint: accessibilityHint, accessibilityState: { selected, disabled }, disabled: disabled, onPress: () => { if (!disabled)
116
+ onActivate(); }, style: ({ pressed }) => [minimumTargetStyle, {
117
+ opacity: disabled ? cardRecipe.interaction.disabledOpacity : pressed ? cardRecipe.interaction.pressedOpacity : 1,
118
+ }, layoutStyle], children: frame });
111
119
  }
112
- export function ListRow({ title, description, leading, trailing, titleMetadata, trailingAction, trailingText, metadataLabel, trailingLabel, onPress, accessibilityLabel, accessibilityHint, disabled = false, density = listRowRecipe.defaults.density, selected: selectedProp, leadingShape = "square", layoutStyle, leadingStyle, contentStyle, titleStyle, titleRowStyle, descriptionStyle, trailingStyle, trailingActionStyle, containerProps, accessibilityState, ...forwarded }) {
120
+ export function ListRow({ title, tone = listRowRecipe.defaults.tone, description, leading, trailing, titleMetadata, trailingAction, trailingText, metadataLabel, trailingLabel, onPress, accessibilityLabel, accessibilityHint, disabled = false, density = listRowRecipe.defaults.density, loading = false, loadingLabel, selected: selectedProp, leadingShape = "square", layoutStyle, leadingStyle, contentStyle, titleRowStyle, trailingStyle, trailingActionStyle, containerProps, accessibilityState, ...forwarded }) {
121
+ assertNoRemovedStyleProps("ListRow", forwarded, ["titleStyle", "descriptionStyle"]);
113
122
  const { hjmTitleEmphasis, ...props } = forwarded;
114
- warnDeprecatedStyleProps("ListRow", { titleStyle, descriptionStyle }, "density/selected and the listRowRecipe typography for appearance");
115
123
  const theme = useHjmNativeTheme();
116
124
  const metrics = listRowRecipe.density[density];
117
125
  const interactive = onPress !== undefined;
@@ -144,6 +152,15 @@ export function ListRow({ title, description, leading, trailing, titleMetadata,
144
152
  width: listRowRecipe.leadingSize,
145
153
  ...(leadingRadius === null ? {} : { borderRadius: theme.tokens.radius[leadingRadius] }),
146
154
  };
155
+ if (loading) {
156
+ // Search and other collections share ListRow geometry instead of approximating it with
157
+ // loose Skeletons. Never mount placeholder actions or forward touch handlers while loading.
158
+ const placeholder = { backgroundColor: theme.colors.surfaceAlt, borderRadius: theme.tokens.radius.sm };
159
+ 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,
160
+ gap: listRowRecipe.gap, minHeight: visualState.minHeight,
161
+ paddingHorizontal: metrics.paddingHorizontal, paddingVertical: metrics.paddingVertical,
162
+ borderWidth: 1, 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] });
163
+ }
147
164
  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: [
148
165
  {
149
166
  alignItems: "center",
@@ -155,14 +172,12 @@ export function ListRow({ title, description, leading, trailing, titleMetadata,
155
172
  titleRowStyle,
156
173
  ], children: [_jsx(Text, { style: [
157
174
  {
158
- color: resolveColorReference(listRowRecipe.title.color, theme.palette),
175
+ color: resolveColorReference(listRowRecipe.tones[tone].titleColor, theme.palette),
159
176
  flexShrink: 1,
160
177
  fontWeight: hjmTitleEmphasis === "regular" ? fontWeight.regular : listRowRecipe.title.fontWeight,
161
178
  },
162
- titleStyle,
163
179
  ], variant: listRowRecipe.title.textVariant, children: title }), resolvedMetadata === undefined ? null : (_jsx(View, { accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", children: resolvedMetadata }))] }), description ? (_jsx(Text, { style: [
164
180
  { color: resolveColorReference(listRowRecipe.description.color, theme.palette) },
165
- descriptionStyle,
166
181
  ], variant: listRowRecipe.description.textVariant, children: description })) : null] }), trailingText || trailing ? (_jsx(View, { accessible: interactive ? false : undefined, importantForAccessibility: interactive ? "no-hide-descendants" : "auto", style: [{ flexShrink: 0 }, trailingStyle], children: trailingText ? (_jsx(Text, { style: { color: resolveColorReference(listRowRecipe.trailing.textColor, theme.palette) }, variant: listRowRecipe.trailing.textVariant, children: trailingText })) : trailing })) : null] }));
167
182
  const contentStyleFor = (pressed) => [
168
183
  minimumTargetStyle,
@@ -212,10 +227,9 @@ export function ListRow({ title, description, leading, trailing, titleMetadata,
212
227
  trailingActionStyle,
213
228
  ], children: trailingAction })] }));
214
229
  }
215
- export function Avatar({ source, renderImage, name, initials, renderFallback, size = 44, decorative = false, accessibilityLabel, style, imageStyle, layoutStyle, }) {
230
+ export function Avatar({ source, renderImage, name, initials, renderFallback, size = 44, decorative = false, accessibilityLabel, layoutStyle, }) {
216
231
  if (!Number.isFinite(size) || size < 24)
217
232
  throw new RangeError("Avatar size must be at least 24");
218
- warnDeprecatedStyleProps("Avatar", { style, imageStyle }, "layoutStyle for placement and size/renderFallback for appearance");
219
233
  const { colors } = useHjmNativeTheme();
220
234
  const sourceKey = source === undefined ? "none" : resolveImageSourceKey(source);
221
235
  const [failedSource, setFailedSource] = useState(null);
@@ -248,55 +262,55 @@ export function Avatar({ source, renderImage, name, initials, renderFallback, si
248
262
  overflow: "hidden",
249
263
  width: size,
250
264
  },
251
- style,
252
265
  layoutStyle,
253
266
  ], children: source !== undefined && !failed ? (renderImage ? (_jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: { height: size, width: size }, children: renderImage({ source, size, onError: failImage,
254
- fallback: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) }) })) : (_jsx(NativeImage, { accessible: false, onError: failImage, source: source, style: [{ height: size, width: size }, imageStyle] }))) : (_jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) })) }));
267
+ fallback: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) }) })) : (_jsx(NativeImage, { accessible: false, onError: failImage, source: source, style: [{ height: size, width: size }] }))) : (_jsx(View, { accessible: false, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: renderFallback?.({ size, decorative: true }) ?? _jsx(Text, { align: "center", style: { color: colors.contentBrand }, variant: "label", children: fallback }) })) }));
255
268
  }
256
- export function Divider({ orientation = "horizontal", inset = 0, style, layoutStyle }) {
269
+ export function Divider({ orientation = "horizontal", inset = 0, layoutStyle }) {
257
270
  if (!Number.isFinite(inset) || inset < 0)
258
271
  throw new RangeError("Divider inset must be non-negative");
259
- warnDeprecatedStyleProps("Divider", { style }, "layoutStyle for placement and orientation/inset for appearance");
260
272
  const { colors } = useHjmNativeTheme();
261
273
  return (_jsx(View, { accessible: false, style: [
262
274
  orientation === "horizontal"
263
275
  ? { backgroundColor: colors.border, height: 1, marginHorizontal: inset, width: "auto" }
264
276
  : { alignSelf: "stretch", backgroundColor: colors.border, marginVertical: inset, width: 1 },
265
- style,
266
277
  layoutStyle,
267
278
  ] }));
268
279
  }
269
280
  // UI control labels keep the ui font even when their metric variant is body; content still uses reading.
270
- export function Accordion({ label, items, expandedValues, defaultExpandedValues = [], onExpandedValuesChange, multiple = accordionRecipe.defaults.allowsMultipleExpanded, density = accordionRecipe.defaults.density, renderIndicator, style, itemStyle, triggerStyle, titleStyle, indicatorStyle, panelStyle, layoutStyle, }) {
271
- warnDeprecatedStyleProps("Accordion", { style, itemStyle, triggerStyle, titleStyle, indicatorStyle, panelStyle }, "layoutStyle for placement and density/renderIndicator for appearance");
281
+ export function Accordion({ label, items, expandedValues, defaultExpandedValues = [], onExpandedValuesChange, multiple = accordionRecipe.defaults.allowsMultipleExpanded, density = accordionRecipe.defaults.density, renderIndicator, layoutStyle, }) {
272
282
  if (items.length === 0)
273
283
  throw new Error("Accordion requires at least one item");
274
284
  const itemValues = new Set(items.map((item) => item.value));
275
285
  if (itemValues.size !== items.length)
276
286
  throw new TypeError("Accordion values must be unique");
277
- const initial = expandedValues ?? defaultExpandedValues;
278
- if (initial.some((value) => !itemValues.has(value))) {
279
- throw new RangeError("Accordion expanded values must match items");
280
- }
281
- if (!multiple && initial.length > 1) {
282
- throw new RangeError("Accordion only accepts one expanded value unless multiple is true");
283
- }
284
287
  const theme = useHjmNativeTheme();
285
288
  const metrics = accordionRecipe.density[density];
286
289
  const indicatorColor = resolveColorReference(accordionRecipe.indicator.color, theme.palette);
287
- const [expanded, setExpanded] = useControllableState({
290
+ const [storedExpanded, setExpanded] = useControllableState({
288
291
  ...(expandedValues === undefined ? {} : { value: expandedValues }),
289
292
  defaultValue: defaultExpandedValues,
290
293
  ...(onExpandedValuesChange === undefined ? {} : { onChange: onExpandedValuesChange }),
291
294
  });
292
- return (_jsx(View, { accessibilityLabel: label, accessibilityRole: "list", style: [style, layoutStyle], children: items.map((item) => {
295
+ const committed = useRef(false);
296
+ const expanded = expandedValues === undefined && committed.current ? storedExpanded.filter(value => itemValues.has(value)) : storedExpanded;
297
+ if (expanded.some(value => !itemValues.has(value)))
298
+ throw new RangeError("Accordion expanded values must match items");
299
+ if (!multiple && expanded.length > 1)
300
+ throw new RangeError("Accordion only accepts one expanded value unless multiple is true");
301
+ useLayoutEffect(() => {
302
+ committed.current = true;
303
+ // Retire expansion with the deleted item instead of reopening it when its key returns.
304
+ if (expanded.length !== storedExpanded.length)
305
+ setExpanded(expanded);
306
+ }, [expanded, storedExpanded, setExpanded]);
307
+ return (_jsx(View, { accessibilityLabel: label, accessibilityRole: "list", style: [layoutStyle], children: items.map((item) => {
293
308
  const isExpanded = expanded.includes(item.value);
294
309
  return (_jsxs(View, { style: [
295
310
  {
296
311
  borderBottomColor: resolveColorReference(accordionRecipe.divider, theme.palette),
297
312
  borderBottomWidth: 1,
298
313
  },
299
- itemStyle,
300
314
  ], children: [_jsxs(Pressable, { accessibilityHint: item.accessibilityHint, accessibilityLabel: item.accessibilityLabel ?? item.title, accessibilityRole: "button", accessibilityState: { disabled: item.disabled === true, expanded: isExpanded }, ...webOnly(webDisclosureProps(isExpanded, item.disabled === true)), disabled: item.disabled, onPress: () => {
301
315
  if (!theme.environment.reducedMotion) {
302
316
  LayoutAnimation.configureNext({
@@ -327,14 +341,12 @@ export function Accordion({ label, items, expandedValues, defaultExpandedValues
327
341
  paddingHorizontal: accordionRecipe.paddingHorizontal,
328
342
  paddingVertical: metrics.paddingVertical,
329
343
  },
330
- triggerStyle,
331
344
  ], children: [_jsxs(View, { style: { flex: 1, gap: spacing.xxs }, children: [_jsx(Text, { fontRole: "ui", style: [
332
345
  {
333
346
  color: resolveColorReference(accordionRecipe.title.color, theme.palette),
334
347
  fontWeight: accordionRecipe.title.fontWeight,
335
348
  },
336
- titleStyle,
337
- ], variant: accordionRecipe.title.textVariant, children: item.title }), item.description ? _jsx(Text, { tone: "muted", variant: "caption", children: item.description }) : null] }), _jsx(View, { accessible: false, style: indicatorStyle, children: renderIndicator ? (renderIndicator({
349
+ ], variant: accordionRecipe.title.textVariant, children: item.title }), item.description ? _jsx(Text, { tone: "muted", variant: "caption", children: item.description }) : null] }), _jsx(View, { accessible: false, children: renderIndicator ? (renderIndicator({
338
350
  value: item.value,
339
351
  expanded: isExpanded,
340
352
  disabled: item.disabled === true,
@@ -345,12 +357,11 @@ export function Accordion({ label, items, expandedValues, defaultExpandedValues
345
357
  paddingBottom: accordionRecipe.panel.paddingBottom,
346
358
  paddingStart: accordionRecipe.panel.paddingInlineStart,
347
359
  },
348
- panelStyle,
349
360
  ], children: item.content })) : null] }, item.value));
350
361
  }) }));
351
362
  }
352
- export function DescriptionList({ label, descriptor, availableWidth, style, itemStyle, layoutStyle, onLayout, ...props }) {
353
- warnDeprecatedStyleProps("DescriptionList", { style, itemStyle }, "layoutStyle for placement and descriptor.columns for arrangement");
363
+ export function DescriptionList({ label, descriptor, availableWidth, layoutStyle, onLayout, ...props }) {
364
+ assertNoRemovedStyleProps("DescriptionList", props, ["style", "itemStyle"]);
354
365
  const resolved = resolveDescriptionListDescriptor(descriptor);
355
366
  const { width: windowWidth } = useWindowDimensions();
356
367
  const { environment } = useHjmNativeTheme();
@@ -377,9 +388,8 @@ export function DescriptionList({ label, descriptor, availableWidth, style, item
377
388
  flexWrap: "wrap",
378
389
  gap: spacing.sm,
379
390
  },
380
- style,
381
391
  layoutStyle,
382
- ], children: resolved.items.map((item) => (_jsxs(View, { accessibilityLabel: `${item.label}, ${item.value}`, accessible: true, style: [{ gap: spacing.xxs, width: itemWidth }, itemStyle], children: [_jsx(Text, { accessible: false, tone: "muted", variant: "label", children: item.label }), _jsx(Text, { accessible: false, tone: "primary", children: item.value })] }, item.id))) }));
392
+ ], children: resolved.items.map((item) => (_jsxs(View, { accessibilityLabel: `${item.label}, ${item.value}`, accessible: true, style: [{ gap: spacing.xxs, width: itemWidth }], children: [_jsx(Text, { accessible: false, tone: "muted", variant: "label", children: item.label }), _jsx(Text, { accessible: false, tone: "primary", children: item.value })] }, item.id))) }));
383
393
  }
384
394
  function resolveImageSourceKey(source) {
385
395
  if (typeof source === "number")
@@ -404,27 +414,32 @@ export function Image(imageProps) {
404
414
  const resolvedDecorative = descriptor.decorative;
405
415
  const resolvedAccessibilityLabel = descriptor.decorative ? undefined : descriptor.accessibilityLabel;
406
416
  const resolvedResizeMode = nativeResizeModes[descriptor.fit];
407
- const sourceKey = `src:${descriptor.src}`;
408
417
  const source = useMemo(() => sourceAdapter?.(descriptor) ?? { uri: descriptor.src }, [descriptor.accessibilityLabel, descriptor.decorative, descriptor.fit,
409
418
  descriptor.height, descriptor.src, descriptor.width, sourceAdapter]);
410
- const [state, setState] = useState({ sourceKey, status: "loading" });
411
- const status = state.sourceKey === sourceKey ? state.status : "loading";
412
- useEffect(() => {
413
- setState((current) => current.sourceKey === sourceKey
414
- ? current
415
- : { sourceKey, status: "loading" });
416
- }, [sourceKey]);
419
+ // Auth/cache changes can create a new request at the same URL. Compare the
420
+ // resolved source contents, not the inline adapter function's identity.
421
+ const sourceKey = JSON.stringify([descriptor.src, resolveImageSourceKey(source)]);
422
+ // Match the Web image lifecycle: a replaced/unmounted host cannot publish
423
+ // results, including an old A request after the product changes A→B→A.
424
+ const generation = useMemo(() => ({}), [sourceKey]);
425
+ const activeGeneration = useRef(generation);
426
+ useLayoutEffect(() => {
427
+ activeGeneration.current = generation;
428
+ return () => { activeGeneration.current = null; };
429
+ }, [generation]);
430
+ const [state, setState] = useState({ generation, status: "loading" });
431
+ const status = state.generation === generation ? state.status : "loading";
417
432
  const reportLoad = (event) => {
418
- setState((current) => current.sourceKey === sourceKey
419
- ? { sourceKey, status: "loaded" }
420
- : current);
433
+ if (activeGeneration.current !== generation)
434
+ return;
435
+ setState({ generation, status: "loaded" });
421
436
  onLoadStatusChange?.("loaded");
422
437
  onLoad?.(event);
423
438
  };
424
439
  const reportError = (event) => {
425
- setState((current) => current.sourceKey === sourceKey
426
- ? { sourceKey, status: "error" }
427
- : current);
440
+ if (activeGeneration.current !== generation)
441
+ return;
442
+ setState({ generation, status: "error" });
428
443
  onLoadStatusChange?.("error");
429
444
  onError?.(event);
430
445
  };
@@ -518,15 +533,15 @@ const styles = StyleSheet.create({
518
533
  width: glyph.lg,
519
534
  },
520
535
  });
521
- export function CounterBadge({ count, accessibilityLabel, max = counterBadgeRecipe.defaults.max, tone = counterBadgeRecipe.defaults.tone, size = counterBadgeRecipe.defaults.size, variant = counterBadgeRecipe.defaults.variant, style, layoutStyle, }) {
522
- warnDeprecatedStyleProps("CounterBadge", { style }, "layoutStyle for placement and tone/size/variant for appearance");
536
+ export function CounterBadge({ count, accessibilityLabel, max = counterBadgeRecipe.defaults.max, tone = counterBadgeRecipe.defaults.tone, size = counterBadgeRecipe.defaults.size, variant = counterBadgeRecipe.defaults.variant, layoutStyle, }) {
523
537
  if (accessibilityLabel !== undefined && !accessibilityLabel.trim()) {
524
538
  throw new TypeError("CounterBadge accessibilityLabel must not be empty");
525
539
  }
540
+ // A zero count hides the badge, but must not change its Hook call order.
541
+ const { colors } = useHjmNativeTheme();
526
542
  const visibleLabel = formatCounterBadgeCount(count, max);
527
543
  if (visibleLabel === null)
528
544
  return null;
529
- const { colors } = useHjmNativeTheme();
530
545
  const presentation = {
531
546
  danger: { background: colors.dangerFill, content: colors.onDanger },
532
547
  brand: { background: colors.primary, content: colors.onPrimary },
@@ -546,13 +561,12 @@ export function CounterBadge({ count, accessibilityLabel, max = counterBadgeReci
546
561
  minWidth: metrics.minWidth,
547
562
  paddingHorizontal: metrics.paddingHorizontal,
548
563
  },
549
- style,
550
564
  layoutStyle,
551
565
  ], children: _jsx(Text, { accessible: false, align: "center", style: { color: presentation[tone].content, fontWeight: "700" }, variant: "caption", children: visibleLabel }) }));
552
566
  }
553
567
  /** Semantic list container that owns separator rhythm around composed rows. */
554
- export function List({ label, children, separator = listRecipe.defaults.separator, appearance = "plain", style, layoutStyle, ...props }) {
555
- warnDeprecatedStyleProps("List", { style }, "layoutStyle for placement and appearance/separator for appearance");
568
+ export function List({ label, children, separator = listRecipe.defaults.separator, appearance = "plain", layoutStyle, ...props }) {
569
+ assertNoRemovedStyleProps("List", props, ["style"]);
556
570
  const { colors, environment, tokens } = useHjmNativeTheme();
557
571
  const items = Children.toArray(children);
558
572
  const separatorContract = listRecipe.separators[separator];
@@ -569,7 +583,6 @@ export function List({ label, children, separator = listRecipe.defaults.separato
569
583
  }
570
584
  : {}),
571
585
  },
572
- style,
573
586
  layoutStyle,
574
587
  ], children: items.map((item, index) => (_jsxs(View, { children: [item, separatorContract && index < items.length - 1 ? (_jsx(View, { accessible: false, style: {
575
588
  backgroundColor: colors.border,
@@ -579,21 +592,10 @@ export function List({ label, children, separator = listRecipe.defaults.separato
579
592
  } })) : null] }, isValidElement(item) && item.key !== null ? item.key : `hjm-list-${index}`))) }));
580
593
  }
581
594
  export function Statistic(props) {
582
- warnDeprecatedStyleProps("Statistic", {
583
- style: props.style,
584
- labelStyle: props.labelStyle,
585
- valueStyle: props.valueStyle,
586
- affixStyle: props.affixStyle,
587
- trendStyle: props.trendStyle,
588
- hintStyle: props.hintStyle,
589
- }, "layoutStyle for placement and density/presentation for appearance");
590
595
  return renderStatistic(props);
591
596
  }
592
- // StatisticGroup composes Statistic with its own item width and the group's deprecated `itemStyle`.
593
- // Routing through this plain function (called in the same component, so hook order is unchanged)
594
- // keeps those internal values from being reported as caller misuse of Statistic.style. A private
595
- // prop on the public component was rejected because it would leak into the exported type.
596
- function renderStatistic({ descriptor, density = "comfortable", presentation = "plain", contextLabel, accessibilityLabel, composeAccessibilityLabel, renderTrendMark, style, labelStyle, valueStyle, affixStyle, trendStyle, hintStyle, layoutStyle, }) {
597
+ // StatisticGroup reuses this renderer with its calculated layout width.
598
+ function renderStatistic({ descriptor, density = "comfortable", presentation = "plain", contextLabel, accessibilityLabel, composeAccessibilityLabel, renderTrendMark, layoutStyle, }) {
597
599
  const resolved = resolveStatisticDescriptor(descriptor);
598
600
  const theme = useHjmNativeTheme();
599
601
  const densityContract = statisticRecipe.density[density];
@@ -632,14 +634,12 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
632
634
  minWidth: 0,
633
635
  padding: densityContract.padding,
634
636
  },
635
- style,
636
637
  layoutStyle,
637
638
  ], children: [_jsx(Text, { accessible: false, style: [
638
639
  {
639
640
  color: resolveColorReference(statisticRecipe.label.color, theme.palette),
640
641
  fontWeight: statisticRecipe.label.fontWeight,
641
642
  },
642
- labelStyle,
643
643
  ], variant: densityContract.labelVariant, children: resolved.label }), _jsxs(View, { accessible: false, style: {
644
644
  alignItems: "baseline",
645
645
  direction: theme.environment.direction,
@@ -652,7 +652,6 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
652
652
  color: resolveColorReference(statisticRecipe.affix.color, theme.palette),
653
653
  fontWeight: statisticRecipe.affix.fontWeight,
654
654
  },
655
- affixStyle,
656
655
  ], variant: statisticRecipe.affix.textVariant, children: resolved.prefix })) : null, _jsx(Text, { accessible: false, style: [
657
656
  {
658
657
  color: resolveColorReference(statisticRecipe.value.color, theme.palette),
@@ -660,13 +659,11 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
660
659
  fontVariant: ["tabular-nums"],
661
660
  fontWeight: statisticRecipe.value.fontWeight,
662
661
  },
663
- valueStyle,
664
662
  ], variant: densityContract.valueVariant, children: resolved.value }), resolved.suffix ? (_jsx(Text, { accessible: false, style: [
665
663
  {
666
664
  color: resolveColorReference(statisticRecipe.affix.color, theme.palette),
667
665
  fontWeight: statisticRecipe.affix.fontWeight,
668
666
  },
669
- affixStyle,
670
667
  ], variant: statisticRecipe.affix.textVariant, children: resolved.suffix })) : null] }), resolved.trend ? (_jsxs(View, { accessible: false, style: {
671
668
  alignItems: "center",
672
669
  flexDirection: "row",
@@ -679,14 +676,12 @@ function renderStatistic({ descriptor, density = "comfortable", presentation = "
679
676
  flexShrink: 1,
680
677
  fontWeight: statisticRecipe.trend.fontWeight,
681
678
  },
682
- trendStyle,
683
679
  ], variant: statisticRecipe.trend.textVariant, children: resolved.trend.label })] })) : null, resolved.hint ? (_jsx(Text, { accessible: false, style: [
684
680
  { color: resolveColorReference(statisticRecipe.hint.color, theme.palette) },
685
- hintStyle,
686
681
  ], variant: statisticRecipe.hint.textVariant, children: resolved.hint })) : null] }));
687
682
  }
688
- export function StatisticGroup({ label, descriptor, availableWidth, density, presentation, composeAccessibilityLabel, renderTrendMark, style, itemStyle, layoutStyle, onLayout, ...props }) {
689
- warnDeprecatedStyleProps("StatisticGroup", { style, itemStyle }, "layoutStyle for placement and density/presentation for appearance");
683
+ export function StatisticGroup({ label, descriptor, availableWidth, density, presentation, composeAccessibilityLabel, renderTrendMark, layoutStyle, onLayout, ...props }) {
684
+ assertNoRemovedStyleProps("StatisticGroup", props, ["style", "itemStyle"]);
690
685
  validateStatisticGroup(descriptor);
691
686
  const { width: windowWidth } = useWindowDimensions();
692
687
  const { environment } = useHjmNativeTheme();
@@ -725,20 +720,19 @@ export function StatisticGroup({ label, descriptor, availableWidth, density, pre
725
720
  flexWrap: "wrap",
726
721
  gap: statisticRecipe.group.gap,
727
722
  },
728
- style,
729
723
  layoutStyle,
730
- ], 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 }, ...(itemStyle === undefined ? {} : { style: itemStyle }) }, item.id))) }));
724
+ ], 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))) }));
731
725
  }
732
726
  /** Group cell: same render as Statistic without attributing the group's styles to the caller. */
733
727
  function StatisticGroupItem(props) {
734
728
  return renderStatistic(props);
735
729
  }
736
730
  /** Ordered record of completed events; unlike Steps it has no current cursor. */
737
- export function Timeline({ items, composeAccessibleName, style, layoutStyle, ...props }) {
738
- warnDeprecatedStyleProps("Timeline", { style }, "layoutStyle for placement and item tone for appearance");
731
+ export function Timeline({ items, composeAccessibleName, layoutStyle, ...props }) {
732
+ assertNoRemovedStyleProps("Timeline", props, ["style"]);
739
733
  const theme = useHjmNativeTheme();
740
734
  const resolved = resolveTimelineDescriptor({ items }, { composeAccessibleName });
741
- return (_jsx(View, { ...props, style: [{ gap: timelineRecipe.gap }, style, layoutStyle], children: resolved.map((item, index) => {
735
+ return (_jsx(View, { ...props, style: [{ gap: timelineRecipe.gap }, layoutStyle], children: resolved.map((item, index) => {
742
736
  const tone = timelineRecipe.dot.tones[item.tone];
743
737
  const accessibilityLabel = [
744
738
  item.accessibleName,