@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
package/dist/feedback.js CHANGED
@@ -1,6 +1,7 @@
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 { resolveColorReference } from "@hjmds/design-contracts/color-references";
3
- import { easing, glyph, spacing } from "@hjmds/design-contracts/foundations";
4
+ import { easing, fontWeight, glyph, spacing } from "@hjmds/design-contracts/foundations";
4
5
  import { resolveControlAccessibleName, } from "@hjmds/design-contracts/behaviors";
5
6
  import { emptyStateRecipe, noticeRecipe, progressRecipe, skeletonRecipe, toastRecipe, } from "@hjmds/design-contracts/recipes";
6
7
  import { resolveResultDescriptor, resultRecipe, } from "@hjmds/design-contracts/components/result";
@@ -8,11 +9,10 @@ import { liquidToastRecipe, createToastSession, createToastStore, resolveToastDe
8
9
  import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore, } from "react";
9
10
  import { Text as NativeText, AccessibilityInfo, Animated, AppState, Easing, Keyboard, Platform, Pressable, View, useWindowDimensions, } from "react-native";
10
11
  import { Button, IconButton } from "./actions.js";
11
- import { warnDeprecatedStyleProps } from "./internal/deprecated-style.js";
12
12
  import { Text } from "./primitives.js";
13
13
  import { useHjmNativeTheme } from "./provider.js";
14
- export function Notice({ title, description, tone = noticeRecipe.defaults.tone, announcement = "none", icon, renderIcon, action, style, layoutStyle, ...props }) {
15
- warnDeprecatedStyleProps("Notice", { style }, "layoutStyle for placement and tone for appearance");
14
+ export function Notice({ title, description, tone = noticeRecipe.defaults.tone, announcement = "none", icon, renderIcon, action, layoutStyle, ...props }) {
15
+ assertNoRemovedStyleProps("Notice", props, ["style"]);
16
16
  const theme = useHjmNativeTheme();
17
17
  const toneContract = noticeRecipe.tones[tone];
18
18
  const foreground = resolveColorReference(toneContract.foreground, theme.palette);
@@ -38,7 +38,6 @@ export function Notice({ title, description, tone = noticeRecipe.defaults.tone,
38
38
  gap: noticeRecipe.gap,
39
39
  padding: noticeRecipe.padding,
40
40
  },
41
- style,
42
41
  layoutStyle,
43
42
  ], children: [_jsxs(View, { style: {
44
43
  alignItems: "flex-start",
@@ -52,8 +51,8 @@ export function Notice({ title, description, tone = noticeRecipe.defaults.tone,
52
51
  width: glyph[noticeRecipe.iconSize],
53
52
  }, children: resolvedIcon })), _jsxs(View, { style: { flex: 1, gap: noticeRecipe.contentGap, minWidth: 0 }, children: [_jsx(Text, { style: { color: foreground, fontWeight: noticeRecipe.title.fontWeight }, variant: noticeRecipe.title.textVariant, children: title }), description ? (_jsx(Text, { style: { color: resolveColorReference(noticeRecipe.description.color, theme.palette) }, variant: noticeRecipe.description.textVariant, children: description })) : null] })] }), action] }));
54
53
  }
55
- export function EmptyState({ title, description, illustration, action, density = emptyStateRecipe.defaults.density, align = "center", announcement = "none", accessibilityLabel, titleRole = "header", style, illustrationStyle, titleStyle, descriptionStyle, actionStyle, layoutStyle, ...props }) {
56
- warnDeprecatedStyleProps("EmptyState", { style, illustrationStyle, titleStyle, descriptionStyle, actionStyle }, "layoutStyle for placement and density/align for appearance");
54
+ export function EmptyState({ title, description, illustration, action, density = emptyStateRecipe.defaults.density, align = "center", announcement = "none", accessibilityLabel, titleRole = "header", layoutStyle, ...props }) {
55
+ assertNoRemovedStyleProps("EmptyState", props, ["style", "illustrationStyle", "titleStyle", "descriptionStyle", "actionStyle"]);
57
56
  const theme = useHjmNativeTheme();
58
57
  const contentLabel = [title, description].filter(Boolean).join(", ");
59
58
  const announcementText = accessibilityLabel ?? [title, description].filter(Boolean).join(". ");
@@ -77,32 +76,29 @@ export function EmptyState({ title, description, illustration, action, density =
77
76
  paddingHorizontal: emptyStateRecipe.paddingHorizontal,
78
77
  paddingVertical: emptyStateRecipe.density[density].paddingVertical,
79
78
  },
80
- style,
81
79
  layoutStyle,
82
80
  ], children: [announcement === "none" || Platform.OS === "ios" ? null : (_jsx(Text, { accessibilityLabel: announcementText, accessibilityLiveRegion: announcement, accessibilityRole: announcement === "assertive" ? "alert" : undefined, accessible: true, style: { height: 1, opacity: 0, position: "absolute", width: 1 }, children: announcementText })), usesUpperSpacers ? _jsx(View, { accessible: false, style: { flexGrow: 1 } }) : null, illustration ? (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", style: [
83
81
  {
84
82
  alignItems: "center",
85
- height: glyph[emptyStateRecipe.icon.size],
83
+ // Larger illustrations own their intrinsic size; icons retain a minimum frame.
84
+ minHeight: glyph[emptyStateRecipe.icon.size],
86
85
  justifyContent: "center",
87
- width: glyph[emptyStateRecipe.icon.size],
86
+ minWidth: glyph[emptyStateRecipe.icon.size],
88
87
  },
89
- illustrationStyle,
90
88
  ], children: illustration })) : null, title === undefined ? null : _jsx(Text, { align: "center", accessibilityRole: titleRole, style: [
91
89
  {
92
90
  color: resolveColorReference(emptyStateRecipe.title.color, theme.palette),
93
91
  fontWeight: emptyStateRecipe.title.fontWeight,
94
92
  },
95
- titleStyle,
96
93
  ], variant: emptyStateRecipe.title.textVariant, children: title }), description ? (_jsx(Text, { align: "center", style: [
97
94
  {
98
95
  color: resolveColorReference(emptyStateRecipe.description.color, theme.palette),
99
96
  },
100
- descriptionStyle,
101
- ], variant: emptyStateRecipe.description.textVariant, children: description })) : null, action ? _jsx(View, { style: actionStyle, children: action }) : null, usesUpperSpacers ? _jsx(View, { accessible: false, style: { flexGrow: 3 } }) : null] }));
97
+ ], variant: emptyStateRecipe.description.textVariant, children: description })) : null, action ? _jsx(View, { children: action }) : null, usesUpperSpacers ? _jsx(View, { accessible: false, style: { flexGrow: 3 } }) : null] }));
102
98
  }
103
99
  /** Terminal flow outcome with platform announcement and canonical actions. */
104
- export function Result({ status, title, description, actions, renderIcon, style, layoutStyle, ...props }) {
105
- warnDeprecatedStyleProps("Result", { style }, "layoutStyle for placement and status for appearance");
100
+ export function Result({ status, title, description, actions, renderIcon, layoutStyle, ...props }) {
101
+ assertNoRemovedStyleProps("Result", props, ["style"]);
106
102
  const theme = useHjmNativeTheme();
107
103
  const result = resolveResultDescriptor({
108
104
  status,
@@ -134,7 +130,6 @@ export function Result({ status, title, description, actions, renderIcon, style,
134
130
  paddingHorizontal: resultRecipe.paddingHorizontal,
135
131
  paddingVertical: resultRecipe.paddingVertical,
136
132
  },
137
- style,
138
133
  layoutStyle,
139
134
  ], children: [_jsx(View, { accessible: false, style: {
140
135
  alignItems: "center",
@@ -161,8 +156,7 @@ export function Result({ status, title, description, actions, renderIcon, style,
161
156
  marginTop: spacing.xs,
162
157
  }, children: [result.secondaryAction ? (_jsx(Button, { accessibilityLabel: result.secondaryAction.accessibilityLabel, onPress: result.secondaryAction.onAction, tone: "secondary", children: result.secondaryAction.label })) : null, result.primaryAction ? (_jsx(Button, { accessibilityLabel: result.primaryAction.accessibilityLabel, onPress: result.primaryAction.onAction, children: result.primaryAction.label })) : null] })) : null] }));
163
158
  }
164
- export function Progress({ value, max = progressRecipe.defaults.max, label, accessibilityLabel, valueText, accessibilityHint, size = progressRecipe.defaults.size, tone = progressRecipe.defaults.tone, shape = progressRecipe.defaults.shape, children, style, labelStyle, valueStyle, trackStyle, indicatorStyle, layoutStyle, testID, }) {
165
- warnDeprecatedStyleProps("Progress", { style, labelStyle, valueStyle, trackStyle, indicatorStyle }, "layoutStyle for placement and tone/size/shape for appearance");
159
+ export function Progress({ value, max = progressRecipe.defaults.max, label, accessibilityLabel, valueText, accessibilityHint, size = progressRecipe.defaults.size, tone = progressRecipe.defaults.tone, shape = progressRecipe.defaults.shape, children, layoutStyle, testID, }) {
166
160
  if (!Number.isFinite(max) || max <= 0) {
167
161
  throw new RangeError("Progress max must be a positive finite number");
168
162
  }
@@ -178,12 +172,12 @@ export function Progress({ value, max = progressRecipe.defaults.max, label, acce
178
172
  max: 100,
179
173
  ...(percentage === undefined ? {} : { now: percentage }),
180
174
  ...(resolvedValueText === undefined ? {} : { text: resolvedValueText }),
181
- }, testID: testID, style: [{ gap: spacing.xs }, style, layoutStyle], children: [label === undefined ? null : (_jsxs(View, { accessible: false, style: {
175
+ }, testID: testID, style: [{ gap: spacing.xs }, layoutStyle], children: [label === undefined ? null : (_jsxs(View, { accessible: false, style: {
182
176
  alignItems: "center",
183
177
  direction: theme.environment.direction,
184
178
  flexDirection: "row",
185
179
  justifyContent: "space-between",
186
- }, children: [_jsx(Text, { style: labelStyle, variant: "label", children: label }), resolvedValueText ? (_jsx(Text, { style: valueStyle, tone: "muted", variant: "caption", children: resolvedValueText })) : null] })), shape === "circular" ? (_jsxs(View, { accessible: false, style: [
180
+ }, children: [_jsx(Text, { variant: "label", children: label }), resolvedValueText ? (_jsx(Text, { tone: "muted", variant: "caption", children: resolvedValueText })) : null] })), shape === "circular" ? (_jsxs(View, { accessible: false, style: [
187
181
  {
188
182
  alignItems: "center",
189
183
  borderColor: resolveColorReference(progressRecipe.track, theme.palette),
@@ -193,34 +187,27 @@ export function Progress({ value, max = progressRecipe.defaults.max, label, acce
193
187
  justifyContent: "center",
194
188
  width: progressRecipe.circular.sizes[size],
195
189
  },
196
- trackStyle,
197
- ], children: [_jsx(View, { pointerEvents: "none", style: [
198
- {
199
- borderColor: resolveColorReference(progressRecipe.tones[tone], theme.palette),
200
- borderRadius: progressRecipe.circular.sizes[size] / 2,
201
- borderTopColor: "transparent",
202
- borderWidth: progressRecipe.circular.strokeWidth[size],
203
- height: progressRecipe.circular.sizes[size],
204
- position: "absolute",
205
- transform: [{ rotate: `${((percentage ?? 25) / 100) * 360}deg` }],
206
- width: progressRecipe.circular.sizes[size],
207
- },
208
- indicatorStyle,
209
- ] }), children] })) : (_jsx(View, { accessible: false, style: [
190
+ ], children: [[0, 1].map(half => {
191
+ const diameter = progressRecipe.circular.sizes[size];
192
+ const fraction = (percentage ?? 25) / 100;
193
+ const sweep = Math.max(0, Math.min(1, fraction * 2 - half));
194
+ if (sweep === 0)
195
+ return null;
196
+ const left = half === 0 ? diameter / 2 : 0;
197
+ return _jsx(View, { pointerEvents: "none", style: { position: "absolute", top: -progressRecipe.circular.strokeWidth[size], left: left - progressRecipe.circular.strokeWidth[size], width: diameter / 2, height: diameter, overflow: "hidden" }, children: _jsx(View, { style: { position: "absolute", left: -left, width: diameter, height: diameter, transform: [{ rotate: `${(sweep - 1) * 180}deg` }] }, children: _jsx(View, { style: { position: "absolute", left, width: diameter / 2, height: diameter, overflow: "hidden" }, children: _jsx(View, { style: [{ position: "absolute", left: -left, width: diameter, height: diameter, borderRadius: diameter / 2, borderWidth: progressRecipe.circular.strokeWidth[size], borderColor: resolveColorReference(progressRecipe.tones[tone], theme.palette) }] }) }) }) }, half);
198
+ }), children] })) : (_jsx(View, { accessible: false, style: [
210
199
  {
211
200
  backgroundColor: resolveColorReference(progressRecipe.track, theme.palette),
212
201
  borderRadius: theme.tokens.radius[progressRecipe.radius],
213
202
  height: progressRecipe.sizes[size],
214
203
  overflow: "hidden",
215
204
  },
216
- trackStyle,
217
205
  ], children: _jsx(View, { style: [
218
206
  {
219
207
  backgroundColor: resolveColorReference(progressRecipe.tones[tone], theme.palette),
220
208
  height: "100%",
221
209
  width: `${percentage ?? 30}%`,
222
210
  },
223
- indicatorStyle,
224
211
  ] }) }))] }));
225
212
  }
226
213
  export { Spinner } from "./internal/spinner.js";
@@ -232,8 +219,7 @@ export { Spinner } from "./internal/spinner.js";
232
219
  * width/height/radius stay for callers already on the 0.9 train and win over
233
220
  * `shape`. Migration: .changeset/skeleton-pulse-by-default.md
234
221
  */
235
- export function Skeleton({ shape = skeletonRecipe.defaults.shape, animated = skeletonRecipe.defaults.animated, width, height, radius: radiusValue, accessibilityLabel, style, layoutStyle, }) {
236
- warnDeprecatedStyleProps("Skeleton", { style }, "layoutStyle for placement and shape/width/height for appearance");
222
+ export function Skeleton({ shape = skeletonRecipe.defaults.shape, animated = skeletonRecipe.defaults.animated, width, height, radius: radiusValue, accessibilityLabel, layoutStyle, }) {
237
223
  const { environment, palette, tokens } = useHjmNativeTheme();
238
224
  const shapeSpec = skeletonRecipe.shapes[shape];
239
225
  const { duration, easing: easingName, fromOpacity, toOpacity } = skeletonRecipe.animation;
@@ -282,13 +268,33 @@ export function Skeleton({ shape = skeletonRecipe.defaults.shape, animated = ske
282
268
  : toOpacity,
283
269
  width: resolvedWidth,
284
270
  },
285
- style,
286
271
  layoutStyle,
287
272
  ] }));
288
273
  }
274
+ const toastActionAlign = { start: "flex-start", end: "flex-end" };
275
+ // Step dots beside their labels so state never depends on colour alone (WCAG 1.4.1). The spoken message
276
+ // already names the running step (resolveToastDescriptor), so the dots are hidden from assistive technology.
277
+ function ToastProgressRow({ progress }) {
278
+ const theme = useHjmNativeTheme();
279
+ const contract = toastRecipe.progress;
280
+ return (_jsx(View, { style: { alignItems: "center", columnGap: contract.gap, direction: theme.environment.direction, flexDirection: "row", flexWrap: "wrap", marginTop: spacing.xxs, rowGap: spacing.xxs }, children: progress.steps.map((step, index) => {
281
+ const state = index < progress.current ? "done" : index === progress.current ? "current" : "upcoming";
282
+ return (_jsxs(View, { style: { alignItems: "center", flexDirection: "row", gap: spacing.xxs }, children: [_jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
283
+ backgroundColor: resolveColorReference(state === "upcoming" ? contract.upcomingColor : contract.doneColor, theme.palette),
284
+ borderRadius: contract.dotSize / 2,
285
+ height: contract.dotSize,
286
+ transform: [{ scale: state === "current" ? contract.currentScale : 1 }],
287
+ width: contract.dotSize,
288
+ } }), _jsx(Text, { style: {
289
+ color: resolveColorReference(state === "current" ? contract.currentLabelColor : contract.labelColor, theme.palette),
290
+ ...(state === "current" ? { fontWeight: fontWeight.bold } : {}),
291
+ }, variant: contract.textVariant, children: step })] }, `${index}-${step}`));
292
+ }) }));
293
+ }
289
294
  // UI control labels keep the ui font even when their metric variant is body; content still uses reading.
290
- function ToastSurface({ snapshot, managedMotion = false, announces = true, suspended = false, onDismiss, onAction, onExitComplete, onPause, onResume, placement, renderToneIcon, style, }) {
295
+ function ToastSurface({ snapshot, managedMotion = false, announces = true, suspended = false, onDismiss, onAction, onPress, onExitComplete, onPause, onResume, placement, renderToneIcon, style, }) {
291
296
  const resolved = snapshot.descriptor;
297
+ const [pressFocused, setPressFocused] = useState(false);
292
298
  const theme = useHjmNativeTheme();
293
299
  // Managed liquid presentation owns its shadow; ordinary toast chrome follows
294
300
  // the profile floating role, preserving the recipe for consumers without one.
@@ -376,7 +382,16 @@ function ToastSurface({ snapshot, managedMotion = false, announces = true, suspe
376
382
  width: "100%",
377
383
  },
378
384
  style,
379
- ], children: [toastRecipe.toneMark.width > 0 ? (_jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
385
+ ], children: [resolved.press ? (
386
+ // A sibling hit surface lets text/media/padding activate the card while the
387
+ // explicit controls stay separate accessibility targets. Liquid's parent
388
+ // PanResponder can cancel this Pressable when it claims an upward swipe.
389
+ _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: resolved.press.accessibilityLabel, accessibilityHint: resolved.announcement, disabled: snapshot.phase !== "visible" || suspended, onPress: onPress, onFocus: () => { setPressFocused(true); pauseFocus(); }, onBlur: () => { setPressFocused(false); resumeFocus(); }, style: ({ pressed }) => ({
390
+ position: "absolute", top: 0, bottom: 0, start: 0, end: 0,
391
+ borderRadius: surfaceRadius,
392
+ borderWidth: pressFocused || pressed ? toastRecipe.states.focus.width : 0,
393
+ borderColor: resolveColorReference(toastRecipe.states.focus.color, theme.palette),
394
+ }) })) : null, toastRecipe.toneMark.width > 0 ? (_jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
380
395
  backgroundColor: accent,
381
396
  borderRadius: theme.tokens.radius[toastRecipe.toneMark.radius],
382
397
  bottom: 0,
@@ -384,16 +399,23 @@ function ToastSurface({ snapshot, managedMotion = false, announces = true, suspe
384
399
  position: "absolute",
385
400
  top: 0,
386
401
  width: toastRecipe.toneMark.width,
387
- } })) : null, !announces || Platform.OS === "ios" ? null : (_jsx(Text, { accessibilityLabel: resolved.announcement, accessibilityLiveRegion: resolved.priority === "high" ? "assertive" : "polite", accessibilityRole: resolved.priority === "high" ? "alert" : undefined, accessible: true, style: { height: 1, opacity: 0, position: "absolute", width: 1 }, children: resolved.announcement })), managedMotion ? (
388
- // A full-width editorial banner replaces the badge/body/close three-column card.
389
- // Keep only a small status glyph in the heading so long copy owns the entire second row.
390
- _jsxs(View, { style: { gap: spacing.xs, direction: theme.environment.direction }, children: [resolved.title ? _jsxs(View, { style: { flexDirection: "row", alignItems: "flex-start", gap: spacing.xs, paddingEnd: toastRecipe.close.diameter, minHeight: glyph.md }, children: [renderedToneIcon === undefined ? null : _jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: { paddingTop: spacing.xxs, flexShrink: 0 }, children: renderedToneIcon }), _jsx(Text, { variant: "bodyLarge", emphasis: "strong", style: { flex: 1, minWidth: 0, color: theme.colors.text }, children: resolved.title })] }) : null, _jsx(Text, { variant: "body", style: { color: theme.colors.textBody, paddingEnd: resolved.title ? 0 : toastRecipe.close.diameter }, children: resolved.description }), _jsx(View, { style: { position: "absolute", top: -spacing.xs, end: -spacing.xs }, children: closeControl })] })) : (_jsxs(View, { style: {
402
+ } })) : null, !announces || Platform.OS === "ios" ? null : (_jsx(Text, { accessibilityLabel: resolved.announcement, accessibilityLiveRegion: resolved.priority === "high" ? "assertive" : "polite", accessibilityRole: resolved.priority === "high" ? "alert" : undefined, accessible: true, style: { height: 1, opacity: 0, position: "absolute", width: 1 }, children: resolved.announcement })), _jsxs(View, { pointerEvents: resolved.press ? "box-none" : "auto", style: {
391
403
  // Start-aligned so a multi-line or large-text toast keeps its badge beside the title (Web does the same).
392
404
  alignItems: "flex-start",
393
405
  direction: theme.environment.direction,
394
406
  flexDirection: "row",
395
407
  gap: toastRecipe.surface.gap,
396
- }, children: [renderedToneIcon === undefined ? null : (_jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
408
+ }, children: [resolved.media !== null ? (
409
+ // Product media replaces the tone badge in the same column; it is decorative, the copy carries meaning.
410
+ _jsx(View, { pointerEvents: resolved.press ? "none" : "auto", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
411
+ alignItems: "center",
412
+ borderRadius: theme.tokens.radius.full,
413
+ flexShrink: 0,
414
+ height: toastRecipe.media.size,
415
+ justifyContent: "center",
416
+ overflow: "hidden",
417
+ width: toastRecipe.media.size,
418
+ }, children: resolved.media })) : renderedToneIcon === undefined ? null : (_jsx(View, { pointerEvents: resolved.press ? "none" : "auto", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: {
397
419
  alignItems: "center",
398
420
  backgroundColor: badge,
399
421
  borderRadius: theme.tokens.radius[toastRecipe.icon.badgeRadius],
@@ -401,30 +423,28 @@ function ToastSurface({ snapshot, managedMotion = false, announces = true, suspe
401
423
  height: toastRecipe.icon.badgeDiameter,
402
424
  justifyContent: "center",
403
425
  width: toastRecipe.icon.badgeDiameter,
404
- }, children: renderedToneIcon })), _jsxs(View, { style: { alignSelf: "center", flex: 1, gap: toastRecipe.content.gap, minWidth: 0 }, children: [resolved.title ? (_jsx(Text, { style: {
405
- color: resolveColorReference(toastRecipe.title.color, theme.palette),
406
- fontWeight: toastRecipe.title.fontWeight,
407
- }, variant: toastRecipe.title.textVariant, children: resolved.title })) : null, _jsx(Text, { style: { color: resolveColorReference(toastRecipe.description.color, theme.palette) }, variant: toastRecipe.description.textVariant, children: resolved.description })] }), closeControl] })), resolved.action ? (
408
- // 1.10.0: tinted pill aligned to the end (toastRecipe.action) instead of a ghost text button.
409
- _jsx(Pressable, { accessibilityLabel: resolved.action.accessibilityLabel, accessibilityRole: "button", onBlur: resumeFocus, onFocus: pauseFocus, onPress: onAction, style: ({ pressed }) => ({
410
- alignItems: managedMotion ? "flex-start" : "center",
411
- alignSelf: managedMotion ? "stretch" : toastRecipe.action.align === "end" ? "flex-end" : "flex-start",
412
- backgroundColor: managedMotion ? "transparent" : resolveColorReference(toastRecipe.action.background, theme.palette),
413
- borderTopWidth: managedMotion ? 1 : 0,
414
- borderTopColor: theme.colors.border,
415
- borderRadius: managedMotion ? 0 : theme.tokens.radius[toastRecipe.action.radius],
416
- justifyContent: "center",
417
- minHeight: toastRecipe.action.minHeight,
418
- opacity: pressed ? toastRecipe.states.pressedOpacity : 1,
419
- paddingHorizontal: managedMotion ? 0 : toastRecipe.action.paddingHorizontal,
420
- }), children: _jsx(Text, { fontRole: "ui", style: {
421
- color: resolveColorReference(toastRecipe.action.color, theme.palette),
422
- fontWeight: toastRecipe.action.fontWeight,
423
- }, variant: toastRecipe.action.textVariant, children: resolved.action.label }) })) : null] }));
426
+ }, children: renderedToneIcon })), _jsxs(View, { pointerEvents: resolved.press ? "box-none" : "auto", style: { alignSelf: "center", flex: 1, gap: toastRecipe.content.gap, minWidth: 0 }, children: [_jsxs(View, { pointerEvents: resolved.press ? "none" : "auto", style: { gap: toastRecipe.content.gap }, children: [resolved.title ? (_jsx(Text, { style: {
427
+ color: resolveColorReference(toastRecipe.title.color, theme.palette),
428
+ fontWeight: toastRecipe.title.fontWeight,
429
+ }, variant: toastRecipe.title.textVariant, children: resolved.title })) : null, _jsx(Text, { style: { color: resolveColorReference(toastRecipe.description.color, theme.palette) }, variant: toastRecipe.description.textVariant, children: resolved.description }), resolved.progress ? _jsx(ToastProgressRow, { progress: resolved.progress }) : null] }), resolved.action ? (
430
+ // 1.10.0 tinted pill; 1.20 panel: under the copy at the start edge (toastRecipe.action.align).
431
+ _jsx(Pressable, { accessibilityLabel: resolved.action.accessibilityLabel, accessibilityRole: "button", onBlur: resumeFocus, onFocus: pauseFocus, onPress: onAction, style: ({ pressed }) => ({
432
+ alignItems: "center",
433
+ alignSelf: toastActionAlign[toastRecipe.action.align],
434
+ backgroundColor: resolveColorReference(toastRecipe.action.background, theme.palette),
435
+ borderRadius: theme.tokens.radius[toastRecipe.action.radius],
436
+ justifyContent: "center",
437
+ marginTop: spacing.xs,
438
+ minHeight: toastRecipe.action.minHeight,
439
+ opacity: pressed ? toastRecipe.states.pressedOpacity : 1,
440
+ paddingHorizontal: toastRecipe.action.paddingHorizontal,
441
+ }), children: _jsx(Text, { fontRole: "ui", style: {
442
+ color: resolveColorReference(toastRecipe.action.color, theme.palette),
443
+ fontWeight: toastRecipe.action.fontWeight,
444
+ }, variant: toastRecipe.action.textVariant, children: resolved.action.label }) })) : null] }), closeControl] })] }));
424
445
  }
425
446
  /** One Native toast driven by the same exactly-once session as a queued region. */
426
- export function Toast({ descriptor, onDismiss, placement = toastRecipe.defaults.placement, renderToneIcon, style, layoutStyle, }) {
427
- warnDeprecatedStyleProps("Toast", { style }, "layoutStyle for placement and the descriptor tone for appearance");
447
+ export function Toast({ descriptor, onDismiss, placement = toastRecipe.defaults.placement, renderToneIcon, layoutStyle, }) {
428
448
  const descriptorRef = useRef(descriptor);
429
449
  const additionalDismissRef = useRef(onDismiss);
430
450
  descriptorRef.current = descriptor;
@@ -443,29 +463,41 @@ export function Toast({ descriptor, onDismiss, placement = toastRecipe.defaults.
443
463
  });
444
464
  const snapshot = useSyncExternalStore(session.subscribe, session.getSnapshot, session.getSnapshot);
445
465
  const previousDescriptor = useRef(descriptor);
466
+ const lastTime = useRef(performance.now());
467
+ const flushTime = useCallback(() => {
468
+ const now = performance.now();
469
+ const elapsed = Math.max(0, now - lastTime.current);
470
+ lastTime.current = now;
471
+ session.advanceTime(elapsed);
472
+ }, [session]);
446
473
  useEffect(() => {
447
474
  if (previousDescriptor.current !== descriptor) {
475
+ flushTime();
448
476
  session.update(decorate(descriptor));
449
477
  previousDescriptor.current = descriptor;
450
478
  }
451
- }, [decorate, descriptor, session]);
452
- useEffect(() => () => {
453
- session.interrupt();
479
+ }, [decorate, descriptor, session, flushTime]);
480
+ const mountGeneration = useRef(0);
481
+ useEffect(() => {
482
+ const generation = ++mountGeneration.current;
483
+ // StrictMode replays cleanup before reattaching the same session. Interrupt
484
+ // only a real unmount, like ToastRegion's store disposal lifecycle.
485
+ return () => { queueMicrotask(() => { if (mountGeneration.current === generation)
486
+ session.interrupt(); }); };
454
487
  }, [session]);
455
488
  useEffect(() => {
456
489
  if (snapshot.timer.status !== "running" || snapshot.timer.remainingMs === null)
457
490
  return;
458
- const timeout = setTimeout(() => {
459
- session.advanceTime(snapshot.timer.remainingMs ?? 0);
460
- }, snapshot.timer.remainingMs);
491
+ lastTime.current = performance.now();
492
+ const timeout = setTimeout(flushTime, snapshot.timer.remainingMs);
461
493
  return () => clearTimeout(timeout);
462
- }, [session, snapshot.timer.remainingMs, snapshot.timer.status]);
494
+ }, [flushTime, snapshot.timer.remainingMs, snapshot.timer.status]);
463
495
  const completeDismiss = (reason) => {
464
496
  session.dismiss(reason);
465
497
  };
466
498
  return (_jsx(ToastSurface, { onAction: () => {
467
499
  session.invokeAction();
468
- }, onDismiss: completeDismiss, onExitComplete: () => session.completeExit(), onPause: (reason) => session.pause(reason), onResume: (reason) => session.resume(reason), placement: placement, ...(renderToneIcon === undefined ? {} : { renderToneIcon }), snapshot: snapshot, style: [style, layoutStyle] }));
500
+ }, onPress: () => { session.invokePress(); }, onDismiss: completeDismiss, onExitComplete: () => session.completeExit(), onPause: (reason) => { flushTime(); session.pause(reason); }, onResume: (reason) => { flushTime(); session.resume(reason); }, placement: placement, ...(renderToneIcon === undefined ? {} : { renderToneIcon }), snapshot: snapshot, style: [layoutStyle] }));
469
501
  }
470
502
  const ToastRegionContext = createContext(null);
471
503
  function useToastKeyboardHeight(enabled) {
@@ -512,6 +544,10 @@ function snapshotDescriptor(snapshot) {
512
544
  dismissOnAction: descriptor.action.dismissOnAction,
513
545
  },
514
546
  }),
547
+ ...(descriptor.press === null ? {} : { press: descriptor.press }),
548
+ // Panel fields must survive the controlled-collection round trip, or `onToastsChange` would drop them.
549
+ ...(descriptor.media === null ? {} : { media: descriptor.media }),
550
+ ...(descriptor.progress === null ? {} : { progress: descriptor.progress }),
515
551
  closeLabel: descriptor.closeLabel,
516
552
  ...(descriptor.onDismiss === null ? {} : { onDismiss: descriptor.onDismiss }),
517
553
  };
@@ -551,8 +587,7 @@ function PresentedToast({ adapter, width, availableHeight, windowOrigin, ...prop
551
587
  return _jsxs(_Fragment, { children: [announcer, _jsx(Surface, { anchor: selected.anchor, snapshot: props.snapshot, width: width, availableHeight: availableHeight, ...(windowOrigin === undefined ? {} : { windowOrigin }), suspended: props.suspended ?? false, body: _jsx(ToastSurface, { ...props, announces: false, managedMotion: true }), fallback: fallback, onPause: props.onPause, onResume: props.onResume, onDismiss: props.onDismiss, onExitComplete: props.onExitComplete })] });
552
588
  }
553
589
  /** Bounded FIFO region with one clock, app-state pause and teardown interruption. */
554
- export function ToastRegion({ presentationAdapter, occluded = false, children, accessibilityLabel, toasts, defaultToasts = [], onToastsChange, maxVisible = toastBehaviorDefaults.maxVisible, maxQueued = toastBehaviorDefaults.maxQueued, duplicatePolicy = toastBehaviorDefaults.duplicatePolicy, timerUpdatePolicy = toastBehaviorDefaults.timerUpdatePolicy, overflowPolicy = toastBehaviorDefaults.overflowPolicy, placement = toastRecipe.defaults.placement, safeAreaInsets = {}, avoidKeyboard = true, keyboardOffset = 0, renderToneIcon, style, toastStyle, layoutStyle, }) {
555
- warnDeprecatedStyleProps("ToastRegion", { style, toastStyle }, "layoutStyle for placement and placement/safeAreaInsets/descriptor tone for appearance");
590
+ export function ToastRegion({ presentationAdapter, occluded = false, children, accessibilityLabel, toasts, defaultToasts = [], onToastsChange, maxVisible = toastBehaviorDefaults.maxVisible, maxQueued = toastBehaviorDefaults.maxQueued, duplicatePolicy = toastBehaviorDefaults.duplicatePolicy, timerUpdatePolicy = toastBehaviorDefaults.timerUpdatePolicy, overflowPolicy = toastBehaviorDefaults.overflowPolicy, placement = toastRecipe.defaults.placement, safeAreaInsets = {}, avoidKeyboard = true, keyboardOffset = 0, renderToneIcon, layoutStyle, }) {
556
591
  if (presentationAdapter && (presentationAdapter.kind !== "liquid" || placement !== "top" || maxVisible !== 1)) {
557
592
  throw new TypeError("Liquid Toast requires top placement and maxVisible=1");
558
593
  }
@@ -718,6 +753,10 @@ export function ToastRegion({ presentationAdapter, occluded = false, children, a
718
753
  }
719
754
  return changed;
720
755
  }, [emitChange, pruneRaw, store]);
756
+ const invokePress = useCallback((id) => {
757
+ flushTime();
758
+ return store.invokePress(id);
759
+ }, [store]);
721
760
  const invokeAction = useCallback((id) => {
722
761
  flushTime();
723
762
  return store.invokeAction(id);
@@ -739,7 +778,7 @@ export function ToastRegion({ presentationAdapter, occluded = false, children, a
739
778
  : "center";
740
779
  const blockOffset = toastRecipe.viewport.inset
741
780
  + (bottomPlacement ? safeBottom + keyboardHeight + keyboardOffset : safeTop);
742
- return (_jsx(ToastRegionContext.Provider, { value: controller, children: _jsxs(View, { style: [{ flex: hasChildren ? 1 : undefined }, style, layoutStyle], children: [children, _jsx(View, { ref: viewportRef, onLayout: event => {
781
+ return (_jsx(ToastRegionContext.Provider, { value: controller, children: _jsxs(View, { style: [{ flex: hasChildren ? 1 : undefined }, layoutStyle], children: [children, _jsx(View, { ref: viewportRef, onLayout: event => {
743
782
  setViewportWidth(event.nativeEvent.layout.width);
744
783
  viewportRef.current?.measureInWindow?.((x, y) => setWindowOrigin(previous => previous?.x === x && previous?.y === y ? previous : { x, y }));
745
784
  }, accessibilityLabel: accessibilityLabel, accessibilityElementsHidden: suspended, importantForAccessibility: suspended ? "no-hide-descendants" : "auto", pointerEvents: suspended ? "none" : "box-none", style: {
@@ -754,7 +793,7 @@ export function ToastRegion({ presentationAdapter, occluded = false, children, a
754
793
  start: toastRecipe.viewport.inset + safeStart,
755
794
  zIndex: toastRecipe.viewport.layer,
756
795
  ...(bottomPlacement ? { bottom: blockOffset } : { top: blockOffset }),
757
- }, children: snapshot.visible.map((entry) => (_jsx(PresentedToast, { adapter: presentationAdapter, width: width, availableHeight: availableHeight, windowOrigin: windowOrigin, suspended: suspended, onAction: () => invokeAction(entry.descriptor.id), onDismiss: (reason) => dismiss(entry.descriptor.id, reason), onExitComplete: () => completeExit(entry.descriptor.id), onPause: (reason) => { controller.pause(entry.descriptor.id, reason); }, onResume: (reason) => { controller.resume(entry.descriptor.id, reason); }, placement: placement, ...(renderToneIcon === undefined ? {} : { renderToneIcon }), snapshot: entry, style: toastStyle }, entry.descriptor.id))) })] }) }));
796
+ }, children: snapshot.visible.map((entry) => (_jsx(PresentedToast, { adapter: presentationAdapter, width: width, availableHeight: availableHeight, windowOrigin: windowOrigin, suspended: suspended, onAction: () => invokeAction(entry.descriptor.id), onPress: () => invokePress(entry.descriptor.id), onDismiss: (reason) => dismiss(entry.descriptor.id, reason), onExitComplete: () => completeExit(entry.descriptor.id), onPause: (reason) => { controller.pause(entry.descriptor.id, reason); }, onResume: (reason) => { controller.resume(entry.descriptor.id, reason); }, placement: placement, ...(renderToneIcon === undefined ? {} : { renderToneIcon }), snapshot: entry }, entry.descriptor.id))) })] }) }));
758
797
  }
759
798
  export function useToastRegion() {
760
799
  const controller = useContext(ToastRegionContext);
@@ -762,4 +801,8 @@ export function useToastRegion() {
762
801
  throw new Error("useToastRegion must be used inside ToastRegion");
763
802
  return controller;
764
803
  }
804
+ // ActivityChip is a feedback-category status trigger (its panel is the Toast in this module). Also exported here so
805
+ // apps can import it from an existing subpath: Next dev with HJM_LOCAL_SOURCE rejected the new ./activity-chip
806
+ // subpath before aliasing because the installed release lacks it (BurnTok 2026-10-10).
807
+ export { ActivityChip } from "./activity-chip.js";
765
808
  //# sourceMappingURL=feedback.js.map