@hanzogui/dialog 3.0.1 → 7.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzogui/dialog",
3
- "version": "3.0.1",
3
+ "version": "7.0.0",
4
4
  "source": "src/index.ts",
5
5
  "files": [
6
6
  "src",
@@ -30,33 +30,33 @@
30
30
  "access": "public"
31
31
  },
32
32
  "scripts": {
33
- "build": "hanzo-gui-build",
34
- "watch": "hanzo-gui-build --watch",
35
- "clean": "hanzo-gui-build clean",
36
- "clean:build": "hanzo-gui-build clean:build"
33
+ "build": "hanzogui-build",
34
+ "watch": "hanzogui-build --watch",
35
+ "clean": "hanzogui-build clean",
36
+ "clean:build": "hanzogui-build clean:build"
37
37
  },
38
38
  "dependencies": {
39
- "@hanzogui/adapt": "3.0.0",
40
- "@hanzogui/animate": "3.0.0",
41
- "@hanzogui/animate-presence": "3.0.0",
42
- "@hanzogui/compose-refs": "3.0.0",
43
- "@hanzogui/constants": "3.0.0",
44
- "@hanzogui/core": "3.0.0",
45
- "@hanzogui/create-context": "3.0.0",
46
- "@hanzogui/dismissable": "3.0.0",
47
- "@hanzogui/focus-scope": "3.0.0",
48
- "@hanzogui/helpers": "3.0.0",
49
- "@hanzogui/polyfill-dev": "3.0.0",
50
- "@hanzogui/portal": "3.0.0",
51
- "@hanzogui/remove-scroll": "3.0.0",
52
- "@hanzogui/sheet": "3.0.0",
53
- "@hanzogui/stacks": "3.0.0",
54
- "@hanzogui/text": "3.0.0",
55
- "@hanzogui/use-controllable-state": "3.0.0",
56
- "@hanzogui/z-index-stack": "3.0.0"
39
+ "@hanzogui/adapt": "^7.0.0",
40
+ "@hanzogui/animate": "^7.0.0",
41
+ "@hanzogui/animate-presence": "^7.0.0",
42
+ "@hanzogui/compose-refs": "^7.0.0",
43
+ "@hanzogui/constants": "^7.0.0",
44
+ "@hanzogui/core": "^7.0.0",
45
+ "@hanzogui/create-context": "^7.0.0",
46
+ "@hanzogui/dismissable": "^7.0.0",
47
+ "@hanzogui/focus-scope": "^7.0.0",
48
+ "@hanzogui/helpers": "^7.0.0",
49
+ "@hanzogui/polyfill-dev": "^7.0.0",
50
+ "@hanzogui/portal": "^7.0.0",
51
+ "@hanzogui/remove-scroll": "^7.0.0",
52
+ "@hanzogui/sheet": "^7.0.0",
53
+ "@hanzogui/stacks": "^7.0.0",
54
+ "@hanzogui/text": "^7.0.0",
55
+ "@hanzogui/use-controllable-state": "^7.0.0",
56
+ "@hanzogui/z-index-stack": "^7.0.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@hanzogui/build": "3.0.0",
59
+ "@hanzogui/build": "^7.0.0",
60
60
  "react": ">=19",
61
61
  "react-native": "0.83.2"
62
62
  },
@@ -65,4 +65,4 @@
65
65
  "react-native": "*"
66
66
  },
67
67
  "module:jsx": "dist/jsx"
68
- }
68
+ }
package/src/Dialog.tsx CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  import { Animate } from '@hanzogui/animate'
10
10
  import { composeRefs, useComposedRefs } from '@hanzogui/compose-refs'
11
11
  import { isWeb, useIsomorphicLayoutEffect } from '@hanzogui/constants'
12
- import type { GetProps, GuiElement, ViewProps } from '@hanzogui/core'
12
+ import type { GetProps, HanzoguiElement, ViewProps } from '@hanzogui/core'
13
13
  import {
14
14
  createStyledContext,
15
15
  getExpandedShorthand,
@@ -75,8 +75,8 @@ type DialogContextValue = {
75
75
  forceMount?: boolean
76
76
  keepChildrenMounted?: boolean
77
77
  disableRemoveScroll?: boolean
78
- triggerRef: React.RefObject<GuiElement | null>
79
- contentRef: React.RefObject<GuiElement | null>
78
+ triggerRef: React.RefObject<HanzoguiElement | null>
79
+ contentRef: React.RefObject<HanzoguiElement | null>
80
80
  contentId: string
81
81
  titleId: string
82
82
  descriptionId: string
@@ -98,6 +98,18 @@ export const DialogContext = createStyledContext<DialogContextValue>(
98
98
  export const { useStyledContext: useDialogContext, Provider: DialogProvider } =
99
99
  DialogContext
100
100
 
101
+ /**
102
+ * Tracks whether the Sheet adapted from a Dialog has finished its slide-out
103
+ * animation. DialogSheetController owns the state; DialogContent reads it so
104
+ * it can hold adapted children mounted until the sheet is fully off-screen,
105
+ * instead of tearing them down the moment Dialog.open flips false.
106
+ *
107
+ * Default true so the value is "safe to unmount" if no provider is mounted
108
+ * (matches the historical behavior where adapted children unmount immediately
109
+ * on close in native).
110
+ */
111
+ const DialogAdaptHiddenContext = React.createContext(true)
112
+
101
113
  /* -------------------------------------------------------------------------------------------------
102
114
  * DialogTrigger
103
115
  * -----------------------------------------------------------------------------------------------*/
@@ -176,7 +188,7 @@ export const DialogPortalFrame = styled(YStack, {
176
188
  } as const,
177
189
 
178
190
  defaultVariants: {
179
- unstyled: process.env.HANZO_GUI_HEADLESS === '1',
191
+ unstyled: process.env.HANZOGUI_HEADLESS === '1',
180
192
  },
181
193
  })
182
194
 
@@ -218,10 +230,10 @@ const DialogPortalItem = ({
218
230
  )
219
231
  }
220
232
 
221
- const DialogPortal = React.forwardRef<GuiElement, DialogPortalProps>(
233
+ const DialogPortal = React.forwardRef<HanzoguiElement, DialogPortalProps>(
222
234
  (props, forwardRef) => {
223
235
  const { scope, forceMount, children, ...frameProps } = props
224
- const dialogRef = React.useRef<GuiElement>(null)
236
+ const dialogRef = React.useRef<HanzoguiElement>(null)
225
237
  const ref = composeRefs(dialogRef, forwardRef)
226
238
 
227
239
  const context = useDialogContext(scope)
@@ -371,7 +383,7 @@ export const DialogOverlayFrame = styled(YStack, {
371
383
  } as const,
372
384
 
373
385
  defaultVariants: {
374
- unstyled: process.env.HANZO_GUI_HEADLESS === '1',
386
+ unstyled: process.env.HANZOGUI_HEADLESS === '1',
375
387
  },
376
388
  })
377
389
 
@@ -450,7 +462,7 @@ const DialogContentFrame = styled(ThemeableStack, {
450
462
 
451
463
  defaultVariants: {
452
464
  size: '$true',
453
- unstyled: process.env.HANZO_GUI_HEADLESS === '1',
465
+ unstyled: process.env.HANZOGUI_HEADLESS === '1',
454
466
  },
455
467
  })
456
468
 
@@ -496,9 +508,9 @@ type DialogContentTypeProps = DialogContentImplProps & {
496
508
  context: DialogContextValue
497
509
  }
498
510
 
499
- const DialogContentModal = React.forwardRef<GuiElement, DialogContentTypeProps>(
511
+ const DialogContentModal = React.forwardRef<HanzoguiElement, DialogContentTypeProps>(
500
512
  ({ children, context, ...props }, forwardedRef) => {
501
- const contentRef = React.useRef<GuiElement>(null)
513
+ const contentRef = React.useRef<HanzoguiElement>(null)
502
514
  const composedRefs = useComposedRefs(forwardedRef, context.contentRef, contentRef)
503
515
 
504
516
  return (
@@ -543,7 +555,7 @@ const DialogContentModal = React.forwardRef<GuiElement, DialogContentTypeProps>(
543
555
 
544
556
  /* -----------------------------------------------------------------------------------------------*/
545
557
 
546
- const DialogContentNonModal = React.forwardRef<GuiElement, DialogContentTypeProps>(
558
+ const DialogContentNonModal = React.forwardRef<HanzoguiElement, DialogContentTypeProps>(
547
559
  (props, forwardedRef) => {
548
560
  const hasInteractedOutsideRef = React.useRef(false)
549
561
 
@@ -615,7 +627,7 @@ type DialogContentImplExtraProps = Omit<DismissableProps, 'onDismiss'> & {
615
627
 
616
628
  type DialogContentImplProps = DialogContentFrameProps & DialogContentImplExtraProps
617
629
 
618
- const DialogContentImpl = React.forwardRef<GuiElement, DialogContentImplProps>(
630
+ const DialogContentImpl = React.forwardRef<HanzoguiElement, DialogContentImplProps>(
619
631
  (props, forwardedRef) => {
620
632
  const {
621
633
  trapFocus,
@@ -630,14 +642,21 @@ const DialogContentImpl = React.forwardRef<GuiElement, DialogContentImplProps>(
630
642
  ...contentProps
631
643
  } = props
632
644
 
633
- const contentRef = React.useRef<GuiElement>(null)
645
+ const contentRef = React.useRef<HanzoguiElement>(null)
634
646
  const composedRefs = useComposedRefs(forwardedRef, contentRef)
635
647
  const isAdapted = useAdaptIsActive(context.adaptScope)
636
648
 
637
649
  // TODO this will re-parent, ideally we would not change tree structure
638
650
 
651
+ // when adapted, the dialog's content is portaled into the Sheet via
652
+ // Adapt.Contents. hold children mounted until the sheet's slide-out
653
+ // animation is fully complete (DialogAdaptHiddenContext is flipped by
654
+ // DialogSheetController via SheetController.onAnimationComplete), then
655
+ // unmount. opt out with `keepChildrenMounted` if you need the old
656
+ // permanent-mount behavior.
657
+ const isAdaptFullyHidden = React.useContext(DialogAdaptHiddenContext)
639
658
  if (isAdapted) {
640
- if (!isWeb && !context.open) {
659
+ if (!context.open && !context.keepChildrenMounted && isAdaptFullyHidden) {
641
660
  return null
642
661
  }
643
662
 
@@ -828,7 +847,7 @@ const TitleWarning: React.FC<TitleWarningProps> = ({ titleId }) => {
828
847
  const DESCRIPTION_WARNING_NAME = 'DialogDescriptionWarning'
829
848
 
830
849
  type DescriptionWarningProps = {
831
- contentRef: React.RefObject<GuiElement>
850
+ contentRef: React.RefObject<HanzoguiElement>
832
851
  descriptionId?: string
833
852
  }
834
853
 
@@ -889,8 +908,8 @@ const Dialog = withStaticProperties(
889
908
  const titleId = `${dialogId}-title`
890
909
  const descriptionId = `${dialogId}-description`
891
910
 
892
- const triggerRef = React.useRef<GuiElement>(null)
893
- const contentRef = React.useRef<GuiElement>(null)
911
+ const triggerRef = React.useRef<HanzoguiElement>(null)
912
+ const contentRef = React.useRef<HanzoguiElement>(null)
894
913
 
895
914
  const [open, setOpen] = useControllableState({
896
915
  prop: openProp,
@@ -969,6 +988,27 @@ const DialogSheetController = (
969
988
  const context = useDialogContext(props.scope)
970
989
  const isAdapted = useAdaptIsActive(context.adaptScope)
971
990
 
991
+ // tracks whether the adapted Sheet has finished its slide-out animation.
992
+ // starts true (= safe to unmount) when the dialog is closed; flips to
993
+ // false the moment the dialog opens; flips back to true when the sheet
994
+ // signals onAnimationComplete with open=false (i.e. slide-out finished).
995
+ const [isAdaptFullyHidden, setIsAdaptFullyHidden] = React.useState(!context.open)
996
+ // mirror context.open into the hidden flag during render — an opening
997
+ // dialog must immediately mark its children as not-hidden so they render
998
+ // for the enter animation.
999
+ if (context.open && isAdaptFullyHidden) {
1000
+ setIsAdaptFullyHidden(false)
1001
+ }
1002
+
1003
+ const handleSheetAnimationComplete = React.useCallback(
1004
+ ({ open }: { open: boolean }) => {
1005
+ if (!open) {
1006
+ setIsAdaptFullyHidden(true)
1007
+ }
1008
+ },
1009
+ []
1010
+ )
1011
+
972
1012
  return (
973
1013
  <SheetController
974
1014
  onOpenChange={(val) => {
@@ -976,10 +1016,13 @@ const DialogSheetController = (
976
1016
  props.onOpenChange?.(val)
977
1017
  }
978
1018
  }}
1019
+ onAnimationComplete={handleSheetAnimationComplete}
979
1020
  open={context.open}
980
1021
  hidden={!isAdapted}
981
1022
  >
982
- {props.children}
1023
+ <DialogAdaptHiddenContext.Provider value={isAdaptFullyHidden}>
1024
+ {props.children}
1025
+ </DialogAdaptHiddenContext.Provider>
983
1026
  </SheetController>
984
1027
  )
985
1028
  }