@hjmds/react-native 1.29.0 → 1.31.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 (88) hide show
  1. package/dist/auth-screen.d.ts +10 -1
  2. package/dist/auth-screen.d.ts.map +1 -1
  3. package/dist/auth-screen.js +39 -24
  4. package/dist/auth-screen.js.map +1 -1
  5. package/dist/carousel.d.ts +25 -1
  6. package/dist/carousel.d.ts.map +1 -1
  7. package/dist/carousel.js +18 -4
  8. package/dist/carousel.js.map +1 -1
  9. package/dist/data-display.d.ts +5 -1
  10. package/dist/data-display.d.ts.map +1 -1
  11. package/dist/data-display.js +28 -14
  12. package/dist/data-display.js.map +1 -1
  13. package/dist/data-table.d.ts.map +1 -1
  14. package/dist/data-table.js +13 -8
  15. package/dist/data-table.js.map +1 -1
  16. package/dist/evidence.d.ts +3 -1562
  17. package/dist/evidence.d.ts.map +1 -1
  18. package/dist/evidence.js +93 -255
  19. package/dist/evidence.js.map +1 -1
  20. package/dist/forms.js +3 -3
  21. package/dist/forms.js.map +1 -1
  22. package/dist/icon-svg.d.ts +8 -0
  23. package/dist/icon-svg.d.ts.map +1 -0
  24. package/dist/icon-svg.js +22 -0
  25. package/dist/icon-svg.js.map +1 -0
  26. package/dist/image-choice.d.ts +5 -0
  27. package/dist/image-choice.d.ts.map +1 -1
  28. package/dist/image-choice.js +5 -2
  29. package/dist/image-choice.js.map +1 -1
  30. package/dist/index.d.ts +4 -4
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +4 -4
  33. package/dist/index.js.map +1 -1
  34. package/dist/inputs.d.ts.map +1 -1
  35. package/dist/inputs.js +2 -1
  36. package/dist/inputs.js.map +1 -1
  37. package/dist/internal/bottom-navigation-inset.d.ts +21 -0
  38. package/dist/internal/bottom-navigation-inset.d.ts.map +1 -0
  39. package/dist/internal/bottom-navigation-inset.js +28 -0
  40. package/dist/internal/bottom-navigation-inset.js.map +1 -0
  41. package/dist/internal/field-frame.d.ts +11 -1
  42. package/dist/internal/field-frame.d.ts.map +1 -1
  43. package/dist/internal/field-frame.js +17 -1
  44. package/dist/internal/field-frame.js.map +1 -1
  45. package/dist/internal/initial-focus.d.ts +2 -1
  46. package/dist/internal/initial-focus.d.ts.map +1 -1
  47. package/dist/internal/initial-focus.js +11 -3
  48. package/dist/internal/initial-focus.js.map +1 -1
  49. package/dist/internal/media-album.d.ts +48 -0
  50. package/dist/internal/media-album.d.ts.map +1 -0
  51. package/dist/internal/media-album.js +36 -0
  52. package/dist/internal/media-album.js.map +1 -0
  53. package/dist/internal/message-reactions.d.ts +28 -2
  54. package/dist/internal/message-reactions.d.ts.map +1 -1
  55. package/dist/internal/message-reactions.js +25 -6
  56. package/dist/internal/message-reactions.js.map +1 -1
  57. package/dist/navigation.d.ts +12 -2
  58. package/dist/navigation.d.ts.map +1 -1
  59. package/dist/navigation.js +75 -19
  60. package/dist/navigation.js.map +1 -1
  61. package/dist/number-field.d.ts.map +1 -1
  62. package/dist/number-field.js +2 -0
  63. package/dist/number-field.js.map +1 -1
  64. package/dist/overlays.d.ts +39 -1
  65. package/dist/overlays.d.ts.map +1 -1
  66. package/dist/overlays.js +254 -205
  67. package/dist/overlays.js.map +1 -1
  68. package/dist/primitives.d.ts +29 -1
  69. package/dist/primitives.d.ts.map +1 -1
  70. package/dist/primitives.js +18 -3
  71. package/dist/primitives.js.map +1 -1
  72. package/dist/public-exports.generated.d.ts +209 -0
  73. package/dist/public-exports.generated.d.ts.map +1 -0
  74. package/dist/public-exports.generated.js +642 -0
  75. package/dist/public-exports.generated.js.map +1 -0
  76. package/dist/screen-flows.d.ts +104 -12
  77. package/dist/screen-flows.d.ts.map +1 -1
  78. package/dist/screen-flows.js +87 -17
  79. package/dist/screen-flows.js.map +1 -1
  80. package/dist/screens.d.ts +59 -7
  81. package/dist/screens.d.ts.map +1 -1
  82. package/dist/screens.js +89 -19
  83. package/dist/screens.js.map +1 -1
  84. package/dist/steps.d.ts +7 -2
  85. package/dist/steps.d.ts.map +1 -1
  86. package/dist/steps.js +12 -5
  87. package/dist/steps.js.map +1 -1
  88. package/package.json +9 -3
package/dist/overlays.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ScreenBodyInsetContext } from "./internal/screen-body-inset.js";
3
+ // Overlays cover the bottom bar, so screens inside them must not pad for it.
4
+ import { BottomNavigationInsetContext } from "./internal/bottom-navigation-inset.js";
3
5
  import { InitialFocusProvider, useInitialFocusScope, useOverlayLayer } from "./internal/initial-focus.js";
4
6
  import { initialFocusDefaults } from "@hjmds/design-contracts/screen-patterns";
5
7
  import { resolveOriginTransition } from "@hjmds/design-contracts/content-transition";
@@ -12,7 +14,7 @@ import { resolveColorReference } from "@hjmds/design-contracts/color-references"
12
14
  import { backdrop, easing, glyph, spacing } from "@hjmds/design-contracts/foundations";
13
15
  import { actionGroupRecipe, alertDialogRecipe, dialogRecipe, sheetRecipe, } from "@hjmds/design-contracts/recipes";
14
16
  import { useCallback, useEffect, useRef, useState, useSyncExternalStore, } from "react";
15
- import { Animated, Easing, Keyboard, Modal, PanResponder, Platform, ScrollView, Pressable, View, useWindowDimensions, } from "react-native";
17
+ import { Animated, Easing, Keyboard, Modal, PanResponder, Platform, ScrollView, Pressable, StatusBar, View, useWindowDimensions, } from "react-native";
16
18
  import { Button, IconButton } from "./actions.js";
17
19
  import { scheduleAfterNativeModalTeardown, shouldAwaitNativeModalDismiss, } from "./internal/modal-lifecycle.js";
18
20
  import { isDevelopment } from "./internal/diagnostics.js";
@@ -35,8 +37,8 @@ function ModalInteractionBoundary({ visible, onTouchStart, children }) {
35
37
  // BT-QA-027: maximum text made a centered BurnTok confirmation taller than the
36
38
  // window, putting its title/cancel off-screen. Keep full copy in a bounded scroll
37
39
  // and actions outside it; capping fonts or clipping copy would hide the decision.
38
- function DialogScrollBody({ children, gap }) {
39
- return _jsx(ScrollView, { style: { flexGrow: 0, flexShrink: 1 }, contentContainerStyle: { gap }, keyboardShouldPersistTaps: "handled",
40
+ function DialogScrollBody({ children, gap, scrollEnabled = true }) {
41
+ return _jsx(ScrollView, { scrollEnabled: scrollEnabled, style: { flexGrow: 0, flexShrink: 1 }, contentContainerStyle: { gap }, keyboardShouldPersistTaps: "handled",
40
42
  // Positioner owns safe-area clearance.
41
43
  automaticallyAdjustContentInsets: false, automaticallyAdjustKeyboardInsets: false, children: children });
42
44
  }
@@ -152,7 +154,7 @@ function resolveOverlayAccessibleTitle(title, accessibilityTitle) {
152
154
  throw new TypeError("An element `title` requires `accessibilityTitle` for the modal accessible name");
153
155
  }
154
156
  /** Native modal boundary with one reasoned close intent for each user attempt. */
155
- export function Dialog({ open, defaultOpen, onOpenChange, title, accessibilityTitle, description, children, primaryAction, secondaryAction, dismissible = true, busy: externalBusy = false, onActionError, size = dialogRecipe.defaults.size, motionOrigin, closeLabel, returnFocusRef, contentStyle, onShow, initialFocus = initialFocusDefaults.overlay, ...modalProps }) {
157
+ export function Dialog({ open, defaultOpen, onOpenChange, title, accessibilityTitle, description, children, primaryAction, secondaryAction, dismissible = true, busy: externalBusy = false, onActionError, size = dialogRecipe.defaults.size, motionOrigin, closeLabel, returnFocusRef, contentStyle, onShow, initialFocus = initialFocusDefaults.overlay, overlayLayer, scrollEnabled = true, ...modalProps }) {
156
158
  const [actionPending, setActionPending] = useState(null);
157
159
  const actionRun = useRef(null);
158
160
  const busy = externalBusy || actionPending !== null;
@@ -377,64 +379,64 @@ export function Dialog({ open, defaultOpen, onOpenChange, title, accessibilityTi
377
379
  const contentBorder = resolveColorReference(dialogRecipe.content.border, palette);
378
380
  const stackActions = environment.textScale >= 1.6 || windowWidth < 480;
379
381
  // Overlay content is not in the screen body: a bleeding rail inside must not reach for the screen gutter.
380
- return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsx(Modal, { ...modalProps, animationType: "none", onDismiss: () => {
381
- nativeShownRef.current = false;
382
- const pending = pendingExitRef.current;
383
- if (pending)
384
- completeExit(pending.token);
385
- }, onRequestClose: () => requestClose("back"), onShow: (event) => {
386
- nativeShownRef.current = true;
387
- startEnter();
388
- setEntered(true);
389
- onShow?.(event);
390
- }, statusBarTranslucent: true, transparent: true, visible: nativeVisible, children: _jsx(ModalInteractionBoundary, { visible: visible, onTouchStart: focusScope.onTouchStart, children: _jsxs(Animated.View, { onLayout: (event) => keyboardViewport.setModalHeight(event.nativeEvent.layout.height), style: {
391
- flex: 1,
392
- justifyContent: "center",
393
- opacity: motionProgress,
394
- ...viewportPadding,
395
- paddingBottom: keyboardViewport.dockedKeyboard
396
- ? spacing.md + keyboardViewport.keyboardInset
397
- : viewportPadding.paddingBottom,
398
- }, children: [_jsx(Scrim, {}), dismissible ? (_jsx(Pressable, { accessible: false, importantForAccessibility: "no-hide-descendants", onPress: () => requestClose("outside"), style: { bottom: 0, left: 0, position: "absolute", right: 0, top: 0 } })) : null, _jsxs(Animated.View, { ref: originContentRef, onLayout: (event) => {
399
- const { width, height } = event.nativeEvent.layout;
400
- const previous = originLayout.current;
401
- originLayout.current = { width, height };
402
- // Error copy, keyboard or rotation may change the destination after entry.
403
- // Fade instead of returning through stale dimensions; a later open remeasures.
404
- if (previous && (previous.width !== width || previous.height !== height))
405
- setOriginTransform(null);
406
- }, accessibilityLabel: [accessibleTitle, description].filter(Boolean).join(", "), accessibilityState: { busy }, accessibilityViewIsModal: true, importantForAccessibility: "yes", role: "dialog", style: [
407
- {
408
- alignSelf: "center",
409
- backgroundColor: contentBackground,
410
- borderColor: contentBorder,
411
- borderRadius: tokens.radius[dialogRecipe.content.radius],
412
- borderWidth: dialogRecipe.content.borderWidth,
413
- ...resolveNativeShadowElevation(surfaceShadow, designProfile !== undefined, 8),
414
- gap: dialogRecipe.content.gap,
415
- maxWidth: sizeRecipe.maxWidth,
416
- maxHeight: "100%",
417
- flexShrink: 1,
418
- padding: sizeRecipe.padding,
419
- shadowColor: surfaceShadow.color,
420
- shadowOffset: { width: 0, height: surfaceShadow.offsetY },
421
- shadowOpacity: surfaceShadow.opacity,
422
- shadowRadius: surfaceShadow.radius,
423
- width: "100%",
424
- },
425
- originTransform && !environment.reducedMotion ? { transform: [
426
- { translateX: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.translateX, 0] }) },
427
- { translateY: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.translateY, 0] }) },
428
- { scaleX: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.scaleX, 1] }) },
429
- { scaleY: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.scaleY, 1] }) },
430
- ] } : undefined,
431
- contentStyle,
432
- ], children: [_jsxs(View, { style: { flexShrink: 1, gap: description ? spacing.xs : dialogRecipe.content.gap }, children: [_jsxs(View, { style: {
433
- alignItems: "flex-start",
434
- direction: environment.direction,
435
- flexDirection: "row",
436
- gap: spacing.sm,
437
- }, children: [_jsx(View, { style: { flex: 1 }, children: _jsx(Text, { accessibilityRole: "header", tone: "primary", variant: "title", children: title }) }), dismissible ? (_jsx(IconButton, { disabled: busy, label: closeLabel, onPress: () => requestClose("close-action"), children: _jsx(CloseGlyph, {}) })) : null] }), description || children ? (_jsxs(DialogScrollBody, { gap: dialogRecipe.content.gap, children: [description ? _jsx(Text, { tone: "muted", children: description }) : null, _jsx(KeyboardAvoidanceContext.Provider, { value: true, children: children })] })) : null] }), _jsx(OverlayActions, { busy: busy, onAction: runAction, pendingAction: actionPending, stacked: stackActions, ...(primaryAction === undefined ? {} : { primaryAction }), ...(secondaryAction === undefined ? {} : { secondaryAction }) })] })] }) }) }) }) }));
382
+ return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(BottomNavigationInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsx(Modal, { ...modalProps, animationType: "none", onDismiss: () => {
383
+ nativeShownRef.current = false;
384
+ const pending = pendingExitRef.current;
385
+ if (pending)
386
+ completeExit(pending.token);
387
+ }, onRequestClose: () => requestClose("back"), onShow: (event) => {
388
+ nativeShownRef.current = true;
389
+ startEnter();
390
+ setEntered(true);
391
+ onShow?.(event);
392
+ }, statusBarTranslucent: true, transparent: true, visible: nativeVisible, children: _jsxs(ModalInteractionBoundary, { visible: visible, onTouchStart: focusScope.onTouchStart, children: [_jsxs(Animated.View, { onLayout: (event) => keyboardViewport.setModalHeight(event.nativeEvent.layout.height), style: {
393
+ flex: 1,
394
+ justifyContent: "center",
395
+ opacity: motionProgress,
396
+ ...viewportPadding,
397
+ paddingBottom: keyboardViewport.dockedKeyboard
398
+ ? spacing.md + keyboardViewport.keyboardInset
399
+ : viewportPadding.paddingBottom,
400
+ }, children: [_jsx(Scrim, {}), dismissible ? (_jsx(Pressable, { accessible: false, importantForAccessibility: "no-hide-descendants", onPress: () => requestClose("outside"), style: { bottom: 0, left: 0, position: "absolute", right: 0, top: 0 } })) : null, _jsxs(Animated.View, { ref: originContentRef, onLayout: (event) => {
401
+ const { width, height } = event.nativeEvent.layout;
402
+ const previous = originLayout.current;
403
+ originLayout.current = { width, height };
404
+ // Error copy, keyboard or rotation may change the destination after entry.
405
+ // Fade instead of returning through stale dimensions; a later open remeasures.
406
+ if (previous && (previous.width !== width || previous.height !== height))
407
+ setOriginTransform(null);
408
+ }, accessibilityLabel: [accessibleTitle, description].filter(Boolean).join(", "), accessibilityState: { busy }, accessibilityViewIsModal: true, importantForAccessibility: "yes", role: "dialog", style: [
409
+ {
410
+ alignSelf: "center",
411
+ backgroundColor: contentBackground,
412
+ borderColor: contentBorder,
413
+ borderRadius: tokens.radius[dialogRecipe.content.radius],
414
+ borderWidth: dialogRecipe.content.borderWidth,
415
+ ...resolveNativeShadowElevation(surfaceShadow, designProfile !== undefined, 8),
416
+ gap: dialogRecipe.content.gap,
417
+ maxWidth: sizeRecipe.maxWidth,
418
+ maxHeight: "100%",
419
+ flexShrink: 1,
420
+ padding: sizeRecipe.padding,
421
+ shadowColor: surfaceShadow.color,
422
+ shadowOffset: { width: 0, height: surfaceShadow.offsetY },
423
+ shadowOpacity: surfaceShadow.opacity,
424
+ shadowRadius: surfaceShadow.radius,
425
+ width: "100%",
426
+ },
427
+ originTransform && !environment.reducedMotion ? { transform: [
428
+ { translateX: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.translateX, 0] }) },
429
+ { translateY: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.translateY, 0] }) },
430
+ { scaleX: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.scaleX, 1] }) },
431
+ { scaleY: motionProgress.interpolate({ inputRange: [0, 1], outputRange: [originTransform.scaleY, 1] }) },
432
+ ] } : undefined,
433
+ contentStyle,
434
+ ], children: [_jsxs(View, { style: { flexShrink: 1, gap: description ? spacing.xs : dialogRecipe.content.gap }, children: [_jsxs(View, { style: {
435
+ alignItems: "flex-start",
436
+ direction: environment.direction,
437
+ flexDirection: "row",
438
+ gap: spacing.sm,
439
+ }, children: [_jsx(View, { style: { flex: 1 }, children: _jsx(Text, { accessibilityRole: "header", tone: "primary", variant: "title", children: title }) }), dismissible ? (_jsx(IconButton, { disabled: busy, label: closeLabel, onPress: () => requestClose("close-action"), children: _jsx(CloseGlyph, {}) })) : null] }), description || children ? (_jsxs(DialogScrollBody, { gap: dialogRecipe.content.gap, scrollEnabled: scrollEnabled, children: [description ? _jsx(Text, { tone: "muted", children: description }) : null, _jsx(KeyboardAvoidanceContext.Provider, { value: true, children: children })] })) : null] }), _jsx(OverlayActions, { busy: busy, onAction: runAction, pendingAction: actionPending, stacked: stackActions, ...(primaryAction === undefined ? {} : { primaryAction }), ...(secondaryAction === undefined ? {} : { secondaryAction }) })] })] }), overlayLayer ? _jsx(Animated.View, { pointerEvents: "none", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: { bottom: 0, left: 0, opacity: motionProgress, position: "absolute", right: 0, top: 0 }, children: overlayLayer }) : null] }) }) }) }) }));
438
440
  }
439
441
  /** Contract session owns duplicate confirms, busy dismissal, error and settlement. */
440
442
  export function AlertDialog({ open, defaultOpen, onOpenChange, request, size = alertDialogRecipe.defaults.size, returnFocusRef, onResult, contentStyle, onShow, ...modalProps }) {
@@ -678,66 +680,66 @@ export function AlertDialog({ open, defaultOpen, onOpenChange, request, size = a
678
680
  },
679
681
  ], children: _jsx(Text, { style: { color: confirmContent }, variant: "label", children: request.confirmLabel }) }));
680
682
  // Overlay content is not in the screen body: a bleeding rail inside must not reach for the screen gutter.
681
- return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsx(Modal, { ...modalProps, animationType: "none", onDismiss: () => {
682
- nativeShownRef.current = false;
683
- const pending = pendingExitSessions.current[0];
684
- if (pending)
685
- completeExit(pending.session);
686
- }, onRequestClose: () => cancel("back"), onShow: (event) => { focusLeastDestructive(event); setEntered(true); }, statusBarTranslucent: true, transparent: true, visible: nativeVisible, children: _jsx(ModalInteractionBoundary, { visible: visible, onTouchStart: focusScope.onTouchStart, children: _jsxs(Animated.View, { onLayout: (event) => keyboardViewport.setModalHeight(event.nativeEvent.layout.height), style: {
687
- flex: 1,
688
- justifyContent: "center",
689
- opacity: motionProgress,
690
- ...viewportPadding,
691
- paddingBottom: keyboardViewport.dockedKeyboard
692
- ? spacing.md + keyboardViewport.keyboardInset
693
- : viewportPadding.paddingBottom,
694
- }, children: [_jsx(Scrim, {}), _jsxs(View, { accessibilityLabel: `${request.title}, ${request.description}`, accessibilityState: { busy }, accessibilityViewIsModal: true, importantForAccessibility: "yes", role: "alertdialog", style: [
695
- {
696
- alignSelf: "center",
697
- backgroundColor: contentBackground,
698
- borderColor: contentBorder,
699
- borderRadius: tokens.radius[alertDialogRecipe.content.radius],
700
- borderWidth: alertDialogRecipe.content.borderWidth,
701
- ...resolveNativeShadowElevation(surfaceShadow, designProfile !== undefined, 8),
702
- gap: alertDialogRecipe.content.gap,
703
- maxWidth: sizeRecipe.maxWidth,
704
- maxHeight: "100%",
705
- flexShrink: 1,
706
- padding: sizeRecipe.padding,
707
- shadowColor: surfaceShadow.color,
708
- shadowOffset: {
709
- width: 0,
710
- height: surfaceShadow.offsetY,
683
+ return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(BottomNavigationInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsx(Modal, { ...modalProps, animationType: "none", onDismiss: () => {
684
+ nativeShownRef.current = false;
685
+ const pending = pendingExitSessions.current[0];
686
+ if (pending)
687
+ completeExit(pending.session);
688
+ }, onRequestClose: () => cancel("back"), onShow: (event) => { focusLeastDestructive(event); setEntered(true); }, statusBarTranslucent: true, transparent: true, visible: nativeVisible, children: _jsx(ModalInteractionBoundary, { visible: visible, onTouchStart: focusScope.onTouchStart, children: _jsxs(Animated.View, { onLayout: (event) => keyboardViewport.setModalHeight(event.nativeEvent.layout.height), style: {
689
+ flex: 1,
690
+ justifyContent: "center",
691
+ opacity: motionProgress,
692
+ ...viewportPadding,
693
+ paddingBottom: keyboardViewport.dockedKeyboard
694
+ ? spacing.md + keyboardViewport.keyboardInset
695
+ : viewportPadding.paddingBottom,
696
+ }, children: [_jsx(Scrim, {}), _jsxs(View, { accessibilityLabel: `${request.title}, ${request.description}`, accessibilityState: { busy }, accessibilityViewIsModal: true, importantForAccessibility: "yes", role: "alertdialog", style: [
697
+ {
698
+ alignSelf: "center",
699
+ backgroundColor: contentBackground,
700
+ borderColor: contentBorder,
701
+ borderRadius: tokens.radius[alertDialogRecipe.content.radius],
702
+ borderWidth: alertDialogRecipe.content.borderWidth,
703
+ ...resolveNativeShadowElevation(surfaceShadow, designProfile !== undefined, 8),
704
+ gap: alertDialogRecipe.content.gap,
705
+ maxWidth: sizeRecipe.maxWidth,
706
+ maxHeight: "100%",
707
+ flexShrink: 1,
708
+ padding: sizeRecipe.padding,
709
+ shadowColor: surfaceShadow.color,
710
+ shadowOffset: {
711
+ width: 0,
712
+ height: surfaceShadow.offsetY,
713
+ },
714
+ shadowOpacity: surfaceShadow.opacity,
715
+ shadowRadius: surfaceShadow.radius,
716
+ width: "100%",
711
717
  },
712
- shadowOpacity: surfaceShadow.opacity,
713
- shadowRadius: surfaceShadow.radius,
714
- width: "100%",
715
- },
716
- contentStyle,
717
- ], children: [_jsxs(DialogScrollBody, { gap: spacing.xs, children: [_jsx(Text, { accessibilityRole: "header", tone: "primary", variant: "title", children: request.title }), _jsx(Text, { tone: "muted", children: request.description }), error ? (_jsx(Text, { accessibilityLiveRegion: "assertive", accessibilityRole: "alert", style: { color: errorColor }, children: error })) : null] }), _jsxs(View, { style: {
718
- direction: environment.direction,
719
- flexDirection: stackActions ? "column" : "row",
720
- gap: stackActions
721
- ? alertDialogRecipe.actions.stackedGap
722
- : alertDialogRecipe.actions.gap,
723
- }, children: [stackActions ? confirmAction : null, request.mode === "confirm" ? (_jsx(Pressable, { ref: cancelRef, accessibilityLabel: request.cancelLabel, accessibilityRole: "button", accessibilityState: { disabled: busy }, disabled: busy, onPress: () => cancel("cancel-action"), style: ({ pressed }) => [
724
- minimumTargetStyle,
725
- {
726
- alignItems: "center",
727
- // The cancel action is a quiet outline on the dialog surface. surfaceAlt
728
- // turned it into a tinted slab wherever a product brands that token
729
- // (BurnTok's pale blue, 2026-09-27), competing with the confirm fill.
730
- backgroundColor: colors.bg,
731
- borderColor: colors.border,
732
- borderRadius: tokens.radius.md,
733
- borderWidth: 1,
734
- flex: stackActions ? undefined : 1,
735
- justifyContent: "center",
736
- minWidth: alertDialogRecipe.actions.minButtonWidth,
737
- opacity: busy ? 0.5 : pressed ? 0.86 : 1,
738
- paddingHorizontal: spacing.md,
739
- },
740
- ], children: _jsx(Text, { variant: "label", children: request.cancelLabel }) })) : null, stackActions ? null : confirmAction] })] })] }) }) }) }) }));
718
+ contentStyle,
719
+ ], children: [_jsxs(DialogScrollBody, { gap: spacing.xs, children: [_jsx(Text, { accessibilityRole: "header", tone: "primary", variant: "title", children: request.title }), _jsx(Text, { tone: "muted", children: request.description }), error ? (_jsx(Text, { accessibilityLiveRegion: "assertive", accessibilityRole: "alert", style: { color: errorColor }, children: error })) : null] }), _jsxs(View, { style: {
720
+ direction: environment.direction,
721
+ flexDirection: stackActions ? "column" : "row",
722
+ gap: stackActions
723
+ ? alertDialogRecipe.actions.stackedGap
724
+ : alertDialogRecipe.actions.gap,
725
+ }, children: [stackActions ? confirmAction : null, request.mode === "confirm" ? (_jsx(Pressable, { ref: cancelRef, accessibilityLabel: request.cancelLabel, accessibilityRole: "button", accessibilityState: { disabled: busy }, disabled: busy, onPress: () => cancel("cancel-action"), style: ({ pressed }) => [
726
+ minimumTargetStyle,
727
+ {
728
+ alignItems: "center",
729
+ // The cancel action is a quiet outline on the dialog surface. surfaceAlt
730
+ // turned it into a tinted slab wherever a product brands that token
731
+ // (BurnTok's pale blue, 2026-09-27), competing with the confirm fill.
732
+ backgroundColor: colors.bg,
733
+ borderColor: colors.border,
734
+ borderRadius: tokens.radius.md,
735
+ borderWidth: 1,
736
+ flex: stackActions ? undefined : 1,
737
+ justifyContent: "center",
738
+ minWidth: alertDialogRecipe.actions.minButtonWidth,
739
+ opacity: busy ? 0.5 : pressed ? 0.86 : 1,
740
+ paddingHorizontal: spacing.md,
741
+ },
742
+ ], children: _jsx(Text, { variant: "label", children: request.cancelLabel }) })) : null, stackActions ? null : confirmAction] })] })] }) }) }) }) }) }));
741
743
  }
742
744
  /** Native Sheet applies policy before emitting a concrete dismissal reason. */
743
745
  export function Sheet({ open, defaultOpen, onOpenChange, title, accessibilityTitle, description, children, footer, placement = "bottom", size = sheetRecipe.defaults.size, busy = false, dismissPolicy, closeLabel, returnFocusRef, safeAreaInsets: suppliedSafeAreaInsets, onDismissComplete, contentStyle,
@@ -997,94 +999,141 @@ keyboardAvoidance = true, scrollable = false, showClose, onShow, initialFocus =
997
999
  const contentBackground = resolveColorReference(sheetRecipe.content.background, palette);
998
1000
  const contentBorder = resolveColorReference(sheetRecipe.content.border, palette);
999
1001
  // Overlay content is not in the screen body: a bleeding rail inside must not reach for the screen gutter.
1000
- return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsx(Modal, { ...modalProps, animationType: "none", onDismiss: () => {
1001
- nativeShownRef.current = false;
1002
- const pending = pendingDismissals.current[0];
1003
- if (pending)
1004
- completeDismiss(pending.cycle);
1005
- }, onRequestClose: () => requestClose("back"), onShow: (event) => {
1006
- nativeShownRef.current = true;
1007
- startEnter();
1008
- setEntered(true);
1009
- onShow?.(event);
1010
- }, statusBarTranslucent: true, transparent: true, visible: nativeVisible, children: _jsx(ModalInteractionBoundary, { visible: visible, onTouchStart: focusScope.onTouchStart, children: _jsxs(Animated.View, { onLayout: (event) => setModalHeight(event.nativeEvent.layout.height), style: {
1011
- alignItems: physicalPlacement === "right" ? "flex-end" : "flex-start",
1012
- flex: 1,
1013
- justifyContent: physicalPlacement === "bottom" ? "flex-end" : "flex-start",
1014
- opacity: motionProgress,
1015
- paddingTop: insets.top,
1016
- paddingBottom: keyboardInset,
1017
- }, children: [_jsx(Scrim, {}), policy.dismissible && policy.outsideDismiss ? (
1018
- // Backdrop press closes every sheet by default (2026-10-17 user decision) through the same
1019
- // requestClose path as the handle, so busy and dismissPolicy guards apply. Named by closeLabel.
1020
- _jsx(Pressable, { accessibilityLabel: closeLabel, accessibilityRole: "button", accessibilityState: { disabled: closeBlocked }, disabled: closeBlocked, onPress: () => requestClose("outside"), style: { bottom: 0, left: 0, position: "absolute", right: 0, top: 0 } })) : null, _jsxs(Animated.View, { accessibilityLabel: [accessibleTitle, description].filter(Boolean).join(", "), accessibilityState: { busy }, accessibilityViewIsModal: true, importantForAccessibility: "yes", onAccessibilityEscape: () => requestClose("escape"), onLayout: (event) => { sheetHeight.current = event.nativeEvent.layout.height; }, role: "dialog", style: [
1021
- {
1022
- backgroundColor: contentBackground,
1023
- borderColor: contentBorder,
1024
- borderRadius: tokens.radius[sheetRecipe.content.radius],
1025
- borderBottomLeftRadius: physicalPlacement === "bottom" ? 0 : tokens.radius[sheetRecipe.content.radius],
1026
- borderBottomRightRadius: physicalPlacement === "bottom" ? 0 : tokens.radius[sheetRecipe.content.radius],
1027
- borderWidth: sheetRecipe.content.borderWidth,
1028
- ...resolveNativeShadowElevation(surfaceShadow, designProfile !== undefined, 8),
1029
- gap: sheetRecipe.body.gap,
1030
- // A fixed size ratio drives the height; `auto` lets the content decide
1031
- // and the recipe's maxHeightRatio caps it.
1032
- height: side
1033
- ? availableHeight
1034
- : sizeRatio === null
1002
+ return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(BottomNavigationInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsx(Modal, { ...modalProps, animationType: "none", onDismiss: () => {
1003
+ nativeShownRef.current = false;
1004
+ const pending = pendingDismissals.current[0];
1005
+ if (pending)
1006
+ completeDismiss(pending.cycle);
1007
+ }, onRequestClose: () => requestClose("back"), onShow: (event) => {
1008
+ nativeShownRef.current = true;
1009
+ startEnter();
1010
+ setEntered(true);
1011
+ onShow?.(event);
1012
+ }, statusBarTranslucent: true, transparent: true, visible: nativeVisible, children: _jsx(ModalInteractionBoundary, { visible: visible, onTouchStart: focusScope.onTouchStart, children: _jsxs(Animated.View, { onLayout: (event) => setModalHeight(event.nativeEvent.layout.height), style: {
1013
+ alignItems: physicalPlacement === "right" ? "flex-end" : "flex-start",
1014
+ flex: 1,
1015
+ justifyContent: physicalPlacement === "bottom" ? "flex-end" : "flex-start",
1016
+ opacity: motionProgress,
1017
+ paddingTop: insets.top,
1018
+ paddingBottom: keyboardInset,
1019
+ }, children: [_jsx(Scrim, {}), policy.dismissible && policy.outsideDismiss ? (
1020
+ // Backdrop press closes every sheet by default (2026-10-17 user decision) through the same
1021
+ // requestClose path as the handle, so busy and dismissPolicy guards apply. Named by closeLabel.
1022
+ _jsx(Pressable, { accessibilityLabel: closeLabel, accessibilityRole: "button", accessibilityState: { disabled: closeBlocked }, disabled: closeBlocked, onPress: () => requestClose("outside"), style: { bottom: 0, left: 0, position: "absolute", right: 0, top: 0 } })) : null, _jsxs(Animated.View, { accessibilityLabel: [accessibleTitle, description].filter(Boolean).join(", "), accessibilityState: { busy }, accessibilityViewIsModal: true, importantForAccessibility: "yes", onAccessibilityEscape: () => requestClose("escape"), onLayout: (event) => { sheetHeight.current = event.nativeEvent.layout.height; }, role: "dialog", style: [
1023
+ {
1024
+ backgroundColor: contentBackground,
1025
+ borderColor: contentBorder,
1026
+ borderRadius: tokens.radius[sheetRecipe.content.radius],
1027
+ borderBottomLeftRadius: physicalPlacement === "bottom" ? 0 : tokens.radius[sheetRecipe.content.radius],
1028
+ borderBottomRightRadius: physicalPlacement === "bottom" ? 0 : tokens.radius[sheetRecipe.content.radius],
1029
+ borderWidth: sheetRecipe.content.borderWidth,
1030
+ ...resolveNativeShadowElevation(surfaceShadow, designProfile !== undefined, 8),
1031
+ gap: sheetRecipe.body.gap,
1032
+ // A fixed size ratio drives the height; `auto` lets the content decide
1033
+ // and the recipe's maxHeightRatio caps it.
1034
+ height: side
1035
+ ? availableHeight
1036
+ : sizeRatio === null
1037
+ ? undefined
1038
+ : Math.min(viewportHeight * sizeRatio, availableHeight),
1039
+ maxWidth: side ? 420 : undefined,
1040
+ // maxHeightRatio caps only `auto`. A fixed size is already bounded by availableHeight
1041
+ // (viewport − top inset − keyboard); capping it too stopped `full` at 90% (2026-10-06 follow-up).
1042
+ maxHeight: side || sizeRatio !== null
1043
+ ? availableHeight
1044
+ : Math.min(availableHeight, viewportHeight * sheetRecipe.content.maxHeightRatio),
1045
+ paddingBottom: sheetRecipe.content.paddingBottom + bottomInset,
1046
+ paddingLeft: sheetRecipe.content.paddingHorizontal + insets.left,
1047
+ paddingRight: sheetRecipe.content.paddingHorizontal + insets.right,
1048
+ // The top safe area limits the viewport, rather than adding a second
1049
+ // notch-sized gap inside a sheet anchored to the bottom.
1050
+ paddingTop: sheetRecipe.content.paddingTop,
1051
+ shadowColor: surfaceShadow.color,
1052
+ shadowOffset: {
1053
+ width: 0,
1054
+ height: surfaceShadow.offsetY,
1055
+ },
1056
+ shadowOpacity: surfaceShadow.opacity,
1057
+ shadowRadius: surfaceShadow.radius,
1058
+ transform: environment.reducedMotion
1035
1059
  ? undefined
1036
- : Math.min(viewportHeight * sizeRatio, availableHeight),
1037
- maxWidth: side ? 420 : undefined,
1038
- // maxHeightRatio caps only `auto`. A fixed size is already bounded by availableHeight
1039
- // (viewport − top inset − keyboard); capping it too stopped `full` at 90% (2026-10-06 follow-up).
1040
- maxHeight: side || sizeRatio !== null
1041
- ? availableHeight
1042
- : Math.min(availableHeight, viewportHeight * sheetRecipe.content.maxHeightRatio),
1043
- paddingBottom: sheetRecipe.content.paddingBottom + bottomInset,
1044
- paddingLeft: sheetRecipe.content.paddingHorizontal + insets.left,
1045
- paddingRight: sheetRecipe.content.paddingHorizontal + insets.right,
1046
- // The top safe area limits the viewport, rather than adding a second
1047
- // notch-sized gap inside a sheet anchored to the bottom.
1048
- paddingTop: sheetRecipe.content.paddingTop,
1049
- shadowColor: surfaceShadow.color,
1050
- shadowOffset: {
1051
- width: 0,
1052
- height: surfaceShadow.offsetY,
1060
+ : side
1061
+ ? [{ translateX: translate }]
1062
+ // Two translateY entries compose: the enter/exit motion plus the live drag offset.
1063
+ : [{ translateY: translate }, { translateY: dragOffset }],
1064
+ width: side ? "88%" : "100%",
1053
1065
  },
1054
- shadowOpacity: surfaceShadow.opacity,
1055
- shadowRadius: surfaceShadow.radius,
1056
- transform: environment.reducedMotion
1057
- ? undefined
1058
- : side
1059
- ? [{ translateX: translate }]
1060
- // Two translateY entries compose: the enter/exit motion plus the live drag offset.
1061
- : [{ translateY: translate }, { translateY: dragOffset }],
1062
- width: side ? "88%" : "100%",
1063
- },
1064
- contentStyle,
1065
- ], children: [_jsx(View, { accessible: true, accessibilityRole: "header", accessibilityLabel: accessibleTitle, style: { position: "absolute", top: 0, start: 0, width: 1, height: 1, overflow: "hidden" } }), _jsxs(View, { ...(canSwipe ? dragResponder.panHandlers : {}), style: { flexShrink: 0 }, children: [showHandle && sheetRecipe.handle.visibleByDefault ? (
1066
- // The handle doubles as a close control so switch and screen-reader users need no drag.
1067
- _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: closeLabel, accessibilityState: { disabled: closeBlocked }, disabled: closeBlocked, onPress: () => requestClose("close-action"), hitSlop: spacing.sm, style: { alignSelf: "center", paddingVertical: spacing.xs }, children: _jsx(View, { style: { width: sheetRecipe.handle.width, height: sheetRecipe.handle.height, borderRadius: tokens.radius[sheetRecipe.handle.radius], backgroundColor: resolveColorReference(sheetRecipe.handle.color, palette) } }) })) : null, description || (policy.dismissible && closeVisible) ? (_jsxs(View, { style: {
1068
- alignItems: "center",
1069
- minHeight: sheetRecipe.header.minHeight,
1070
- flexShrink: 0,
1071
- direction: environment.direction,
1072
- flexDirection: "row",
1073
- // Without a description the × keeps its inline-end place (2026-10-17: no visible title).
1074
- justifyContent: "flex-end",
1075
- gap: spacing.sm,
1076
- }, children: [description ? _jsx(View, { style: { flex: 1 }, children: _jsx(Text, { tone: "muted", children: description }) }) : null, policy.dismissible && closeVisible ? (_jsx(IconButton, { disabled: busy && !policy.dismissWhileBusy, label: closeLabel, onPress: () => requestClose("close-action"), children: _jsx(CloseGlyph, {}) })) : null] })) : null] }), scrollable ? (_jsx(ScrollView
1077
- // The sheet's inline padding used to sit outside this clipping viewport, so ListRows cut their surface
1078
- // bleed. The viewport now reaches the padding edge and carries the padding inside its content (Web's
1079
- // body scroll box does the same); content keeps its position (2026-10-17 1.27.2 adoption).
1080
- , {
1066
+ contentStyle,
1067
+ ], children: [_jsx(View, { accessible: true, accessibilityRole: "header", accessibilityLabel: accessibleTitle, style: { position: "absolute", top: 0, start: 0, width: 1, height: 1, overflow: "hidden" } }), _jsxs(View, { ...(canSwipe ? dragResponder.panHandlers : {}), style: { flexShrink: 0 }, children: [showHandle && sheetRecipe.handle.visibleByDefault ? (
1068
+ // The handle doubles as a close control so switch and screen-reader users need no drag.
1069
+ _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: closeLabel, accessibilityState: { disabled: closeBlocked }, disabled: closeBlocked, onPress: () => requestClose("close-action"), hitSlop: spacing.sm, style: { alignSelf: "center", paddingVertical: spacing.xs }, children: _jsx(View, { style: { width: sheetRecipe.handle.width, height: sheetRecipe.handle.height, borderRadius: tokens.radius[sheetRecipe.handle.radius], backgroundColor: resolveColorReference(sheetRecipe.handle.color, palette) } }) })) : null, description || (policy.dismissible && closeVisible) ? (_jsxs(View, { style: {
1070
+ alignItems: "center",
1071
+ minHeight: sheetRecipe.header.minHeight,
1072
+ flexShrink: 0,
1073
+ direction: environment.direction,
1074
+ flexDirection: "row",
1075
+ // Without a description the × keeps its inline-end place (2026-10-17: no visible title).
1076
+ justifyContent: "flex-end",
1077
+ gap: spacing.sm,
1078
+ }, children: [description ? _jsx(View, { style: { flex: 1 }, children: _jsx(Text, { tone: "muted", children: description }) }) : null, policy.dismissible && closeVisible ? (_jsx(IconButton, { disabled: busy && !policy.dismissWhileBusy, label: closeLabel, onPress: () => requestClose("close-action"), children: _jsx(CloseGlyph, {}) })) : null] })) : null] }), scrollable ? (_jsx(ScrollView
1081
1079
  // The sheet's inline padding used to sit outside this clipping viewport, so ListRows cut their surface
1082
1080
  // bleed. The viewport now reaches the padding edge and carries the padding inside its content (Web's
1083
1081
  // body scroll box does the same); content keeps its position (2026-10-17 1.27.2 adoption).
1084
- style: { flexShrink: 1, minHeight: 0, ...bodyFill, ...sheetBodyRoom.viewport }, contentContainerStyle: { gap: sheetRecipe.body.gap, ...sheetBodyRoom.content }, keyboardShouldPersistTaps: "handled", keyboardDismissMode: Platform.OS === "ios" ? "interactive" : "on-drag", automaticallyAdjustKeyboardInsets: false, children: _jsx(KeyboardAvoidanceContext.Provider, { value: keyboardAvoidance, children: children }) })) : _jsx(View, { style: { gap: sheetRecipe.body.gap, flexShrink: 1, ...bodyFill }, children: _jsx(KeyboardAvoidanceContext.Provider, { value: keyboardAvoidance, children: children }) }), footer ? (_jsx(View, { style: {
1085
- gap: sheetRecipe.footer.gap,
1086
- flexShrink: 0,
1087
- paddingTop: sheetRecipe.footer.paddingTop,
1088
- }, children: footer })) : null] })] }) }) }) }) }));
1082
+ , {
1083
+ // The sheet's inline padding used to sit outside this clipping viewport, so ListRows cut their surface
1084
+ // bleed. The viewport now reaches the padding edge and carries the padding inside its content (Web's
1085
+ // body scroll box does the same); content keeps its position (2026-10-17 1.27.2 adoption).
1086
+ style: { flexShrink: 1, minHeight: 0, ...bodyFill, ...sheetBodyRoom.viewport }, contentContainerStyle: { gap: sheetRecipe.body.gap, ...sheetBodyRoom.content }, keyboardShouldPersistTaps: "handled", keyboardDismissMode: Platform.OS === "ios" ? "interactive" : "on-drag", automaticallyAdjustKeyboardInsets: false, children: _jsx(KeyboardAvoidanceContext.Provider, { value: keyboardAvoidance, children: children }) })) : _jsx(View, { style: { gap: sheetRecipe.body.gap, flexShrink: 1, ...bodyFill }, children: _jsx(KeyboardAvoidanceContext.Provider, { value: keyboardAvoidance, children: children }) }), footer ? (_jsx(View, { style: {
1087
+ gap: sheetRecipe.footer.gap,
1088
+ flexShrink: 0,
1089
+ paddingTop: sheetRecipe.footer.paddingTop,
1090
+ }, children: footer })) : null] })] }) }) }) }) }) }));
1091
+ }
1092
+ /**
1093
+ * Edge-to-edge presentation (Dialog companion): a full-screen Modal with the status bar hidden and rotation allowed,
1094
+ * no card, scrim or header. It joins the overlay stack (screens below keep a pending entry focus until it has torn
1095
+ * down), dismisses on back with a reason, and returns accessibility focus after the native dismissal.
1096
+ */
1097
+ export function ImmersiveOverlay({ open, onOpenChange, label, exitLabel, children, tools, status, returnFocusRef, onShow }) {
1098
+ const { palette, environment } = useHjmNativeTheme();
1099
+ const insets = useHjmNativeSafeAreaInsets();
1100
+ const recipe = dialogRecipe.immersive;
1101
+ const [layered, setLayered] = useState(open);
1102
+ const [entered, setEntered] = useState(false);
1103
+ const wasOpen = useRef(open);
1104
+ const shown = useRef(false);
1105
+ const pendingDismiss = useRef(null);
1106
+ const focusScope = useInitialFocusScope({ mode: "none", active: open && entered, layer: useOverlayLayer(layered) });
1107
+ useEffect(() => {
1108
+ if (open) {
1109
+ wasOpen.current = true;
1110
+ pendingDismiss.current = null;
1111
+ setLayered(true);
1112
+ return undefined;
1113
+ }
1114
+ setEntered(false);
1115
+ if (!wasOpen.current)
1116
+ return undefined;
1117
+ wasOpen.current = false;
1118
+ // Leave the stack and return focus once the native window is gone, the point Dialog and Sheet use.
1119
+ const finish = () => { pendingDismiss.current = null; setLayered(false); focusNativeTarget(returnFocusRef); };
1120
+ if (shouldAwaitNativeModalDismiss(shown.current)) {
1121
+ pendingDismiss.current = finish;
1122
+ return undefined;
1123
+ }
1124
+ const task = scheduleAfterNativeModalTeardown(finish);
1125
+ return () => task.cancel();
1126
+ }, [open, returnFocusRef]);
1127
+ const background = resolveColorReference(recipe.background, palette);
1128
+ // The stage is not in a screen body: a bleeding rail inside must not reach for the screen gutter.
1129
+ return (_jsx(ScreenBodyInsetContext.Provider, { value: 0, children: _jsx(InitialFocusProvider, { scope: focusScope, children: _jsxs(Modal, { visible: open,
1130
+ // Animation "none": teardown completion is scheduled after removal, which assumes no built-in exit animation.
1131
+ animationType: "none", presentationStyle: "fullScreen", supportedOrientations: [...recipe.orientations], statusBarTranslucent: true, onRequestClose: () => onOpenChange(false, { reason: "back" }), onShow: (event) => { shown.current = true; setEntered(true); onShow?.(event); }, onDismiss: () => { shown.current = false; pendingDismiss.current?.(); }, children: [_jsx(StatusBar, { hidden: recipe.statusBarHidden }), _jsxs(View, { onTouchStart: focusScope.onTouchStart, accessibilityViewIsModal: true, accessibilityLabel: label, role: "dialog", style: { backgroundColor: background, direction: environment.direction, flex: 1 }, children: [_jsx(View, { style: { flex: 1, overflow: "hidden" }, children: children }), _jsxs(View, { style: {
1132
+ gap: recipe.controls.gap,
1133
+ paddingTop: recipe.controls.padding,
1134
+ paddingBottom: Math.max(recipe.controls.padding, insets.bottom ?? 0),
1135
+ paddingLeft: Math.max(recipe.controls.padding, insets.left ?? 0),
1136
+ paddingRight: Math.max(recipe.controls.padding, insets.right ?? 0),
1137
+ }, children: [status, _jsxs(View, { style: { alignItems: "center", flexDirection: "row", gap: recipe.controls.actionGap }, children: [tools, _jsx(Button, { size: "large", growWithContent: true, layoutStyle: { flex: 1 }, onPress: () => onOpenChange(false, { reason: "exit-action" }), children: exitLabel })] })] })] })] }) }) }));
1089
1138
  }
1090
1139
  //# sourceMappingURL=overlays.js.map