@greatapps/common 1.1.788 → 1.1.789

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 (43) hide show
  1. package/dist/components/account/AccountModals.mjs +3 -6
  2. package/dist/components/account/AccountModals.mjs.map +1 -1
  3. package/dist/components/account/DisableTwoFactorAuthModal.mjs +2 -3
  4. package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
  5. package/dist/components/account/TwoFactorAuthModal.mjs +4 -5
  6. package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
  7. package/dist/components/account/sections/MyProfileSection.mjs +2 -5
  8. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
  9. package/dist/components/layouts/UsersSelectorPopover.mjs +1 -1
  10. package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
  11. package/dist/components/modals/ModalManager.mjs +2 -5
  12. package/dist/components/modals/ModalManager.mjs.map +1 -1
  13. package/dist/components/modals/promo/AiCreditsOfferModal/AiCreditsOfferModal.mjs +2 -3
  14. package/dist/components/modals/promo/AiCreditsOfferModal/AiCreditsOfferModal.mjs.map +1 -1
  15. package/dist/components/ui/overlay/Dialog.mjs +6 -7
  16. package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
  17. package/dist/components/ui/overlay/Popover.mjs +3 -3
  18. package/dist/components/ui/overlay/Popover.mjs.map +1 -1
  19. package/dist/components/ui/overlay/Sheet.mjs +6 -6
  20. package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
  21. package/dist/components/ui/overlay/layers.mjs +44 -18
  22. package/dist/components/ui/overlay/layers.mjs.map +1 -1
  23. package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs +2 -3
  24. package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs.map +1 -1
  25. package/dist/components/widgets/ImageUpload/ImageUpload.mjs +2 -4
  26. package/dist/components/widgets/ImageUpload/ImageUpload.mjs.map +1 -1
  27. package/dist/index.mjs +3 -1
  28. package/dist/index.mjs.map +1 -1
  29. package/package.json +8 -7
  30. package/src/components/account/AccountModals.tsx +3 -9
  31. package/src/components/account/DisableTwoFactorAuthModal.tsx +55 -58
  32. package/src/components/account/TwoFactorAuthModal.tsx +147 -152
  33. package/src/components/account/sections/MyProfileSection.tsx +2 -6
  34. package/src/components/layouts/UsersSelectorPopover.tsx +1 -6
  35. package/src/components/modals/ModalManager.tsx +3 -9
  36. package/src/components/modals/promo/AiCreditsOfferModal/AiCreditsOfferModal.tsx +8 -12
  37. package/src/components/ui/overlay/Dialog.tsx +33 -39
  38. package/src/components/ui/overlay/Popover.tsx +16 -15
  39. package/src/components/ui/overlay/Sheet.tsx +50 -56
  40. package/src/components/ui/overlay/layers.tsx +45 -73
  41. package/src/components/widgets/ImageUpload/ImageTooSmallModal.tsx +20 -23
  42. package/src/components/widgets/ImageUpload/ImageUpload.tsx +11 -15
  43. package/src/index.ts +1 -1
@@ -4,7 +4,6 @@ import { useTranslations } from 'next-intl';
4
4
  import { IconX, IconCopy, IconRefresh } from '@tabler/icons-react';
5
5
  import { Button } from '../ui/buttons/Button';
6
6
  import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../ui/overlay/Dialog';
7
- import { DialogLayer } from '../ui/overlay/layers';
8
7
  import { Separator } from '../ui/data-display/Separator';
9
8
  import { InputOTP, InputOTPGroup, InputOTPSlot } from '../ui/form/InputOtp';
10
9
  import { REGEXP_ONLY_DIGITS } from 'input-otp';
@@ -42,86 +41,17 @@ export default function TwoFactorAuthModal({ open, onClose, onSuccess }: TwoFact
42
41
 
43
42
  if (step === 'recovery') {
44
43
  return (
45
- <DialogLayer>
46
- <Dialog open={open} onOpenChange={handleClose}>
47
- <DialogContent
48
- showCloseButton={false}
49
- className="flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] lg:h-auto lg:rounded-lg lg:border lg:top-[50%] lg:left-[50%] lg:right-auto lg:bottom-auto lg:translate-x-[-50%] lg:translate-y-[-50%]"
50
- >
51
- <DialogHeader className="sr-only">
52
- <DialogTitle>{translate('common.account.twoFactor.recoveryTitle')}</DialogTitle>
53
- </DialogHeader>
54
- <div className="flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
55
- <span className="paragraph-medium-semibold text-gray-950 text-center">
56
- {translate('common.account.twoFactor.recoveryTitle')}
57
- </span>
58
- <Button
59
- type="button"
60
- variant="ghost"
61
- className="size-8! p-0 absolute right-4"
62
- onClick={handleClose}
63
- >
64
- <IconX size={18} />
65
- </Button>
66
- </div>
67
-
68
- <div className="flex flex-col gap-5 lg:gap-6 px-4 lg:px-5 py-5 lg:py-6 flex-1 lg:flex-none">
69
- <div className="flex flex-col gap-2">
70
- <h3 className="paragraph-medium-semibold text-gray-950 max-w-[269px]">
71
- {translate('common.account.twoFactor.recoveryHeading')}
72
- </h3>
73
- <div className="paragraph-small-regular text-gray-600">
74
- <p>{translate('common.account.twoFactor.recoveryText1')}</p>
75
- <br />
76
- <p>{translate('common.account.twoFactor.recoveryText2')}</p>
77
- </div>
78
- </div>
79
-
80
- <div className="bg-gray-50 rounded-lg p-4 flex flex-col gap-4">
81
- <div className="paragraph-small-medium text-gray-950 whitespace-nowrap">
82
- {backupCodes.map((backupCode, i) => (
83
- <p key={i}>{backupCode}</p>
84
- ))}
85
- </div>
86
- <Button
87
- type="button"
88
- variant="secondary"
89
- className="h-8! w-fit"
90
- onClick={handleCopyCodes}
91
- >
92
- <IconCopy size={16} />
93
- {translate('common.account.twoFactor.copyCodes')}
94
- </Button>
95
- </div>
96
- </div>
97
-
98
- <div className="flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between mt-auto lg:mt-0">
99
- <Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
100
- {translate('common.actions.cancel')}
101
- </Button>
102
- <Button className="h-10!" type="button" onClick={handleFinalize}>
103
- {translate('common.account.twoFactor.finish')}
104
- </Button>
105
- </div>
106
- </DialogContent>
107
- </Dialog>
108
- </DialogLayer>
109
- );
110
- }
111
-
112
- return (
113
- <DialogLayer>
114
44
  <Dialog open={open} onOpenChange={handleClose}>
115
45
  <DialogContent
116
46
  showCloseButton={false}
117
- className="flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] lg:h-auto lg:max-h-[90vh] lg:rounded-lg lg:border lg:top-[50%] lg:left-[50%] lg:right-auto lg:bottom-auto lg:translate-x-[-50%] lg:translate-y-[-50%]"
47
+ className="flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] lg:h-auto lg:rounded-lg lg:border lg:top-[50%] lg:left-[50%] lg:right-auto lg:bottom-auto lg:translate-x-[-50%] lg:translate-y-[-50%]"
118
48
  >
119
49
  <DialogHeader className="sr-only">
120
- <DialogTitle>{translate('common.account.twoFactor.title')}</DialogTitle>
50
+ <DialogTitle>{translate('common.account.twoFactor.recoveryTitle')}</DialogTitle>
121
51
  </DialogHeader>
122
- <div className="shrink-0 flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
52
+ <div className="flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
123
53
  <span className="paragraph-medium-semibold text-gray-950 text-center">
124
- {translate('common.account.twoFactor.title')}
54
+ {translate('common.account.twoFactor.recoveryTitle')}
125
55
  </span>
126
56
  <Button
127
57
  type="button"
@@ -133,91 +63,156 @@ export default function TwoFactorAuthModal({ open, onClose, onSuccess }: TwoFact
133
63
  </Button>
134
64
  </div>
135
65
 
136
- <form
137
- className="flex-1 min-h-0 flex flex-col"
138
- onSubmit={(e) => {
139
- e.preventDefault();
140
- if (isCodeComplete) handleSubmit();
141
- }}
66
+ <div className="flex flex-col gap-5 lg:gap-6 px-4 lg:px-5 py-5 lg:py-6 flex-1 lg:flex-none">
67
+ <div className="flex flex-col gap-2">
68
+ <h3 className="paragraph-medium-semibold text-gray-950 max-w-[269px]">
69
+ {translate('common.account.twoFactor.recoveryHeading')}
70
+ </h3>
71
+ <div className="paragraph-small-regular text-gray-600">
72
+ <p>{translate('common.account.twoFactor.recoveryText1')}</p>
73
+ <br />
74
+ <p>{translate('common.account.twoFactor.recoveryText2')}</p>
75
+ </div>
76
+ </div>
77
+
78
+ <div className="bg-gray-50 rounded-lg p-4 flex flex-col gap-4">
79
+ <div className="paragraph-small-medium text-gray-950 whitespace-nowrap">
80
+ {backupCodes.map((backupCode, i) => (
81
+ <p key={i}>{backupCode}</p>
82
+ ))}
83
+ </div>
84
+ <Button
85
+ type="button"
86
+ variant="secondary"
87
+ className="h-8! w-fit"
88
+ onClick={handleCopyCodes}
89
+ >
90
+ <IconCopy size={16} />
91
+ {translate('common.account.twoFactor.copyCodes')}
92
+ </Button>
93
+ </div>
94
+ </div>
95
+
96
+ <div className="flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between mt-auto lg:mt-0">
97
+ <Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
98
+ {translate('common.actions.cancel')}
99
+ </Button>
100
+ <Button className="h-10!" type="button" onClick={handleFinalize}>
101
+ {translate('common.account.twoFactor.finish')}
102
+ </Button>
103
+ </div>
104
+ </DialogContent>
105
+ </Dialog>
106
+ );
107
+ }
108
+
109
+ return (
110
+ <Dialog open={open} onOpenChange={handleClose}>
111
+ <DialogContent
112
+ showCloseButton={false}
113
+ className="flex flex-col p-0 gap-0 max-w-full sm:max-w-full border-0 rounded-t-2xl rounded-b-none h-[100dvh] top-0 bottom-0 left-0 right-0 translate-x-0 translate-y-0 lg:max-w-[470px] lg:h-auto lg:max-h-[90vh] lg:rounded-lg lg:border lg:top-[50%] lg:left-[50%] lg:right-auto lg:bottom-auto lg:translate-x-[-50%] lg:translate-y-[-50%]"
114
+ >
115
+ <DialogHeader className="sr-only">
116
+ <DialogTitle>{translate('common.account.twoFactor.title')}</DialogTitle>
117
+ </DialogHeader>
118
+ <div className="shrink-0 flex items-center justify-center px-4 py-3 relative border-b border-gray-200 lg:border-b-0">
119
+ <span className="paragraph-medium-semibold text-gray-950 text-center">
120
+ {translate('common.account.twoFactor.title')}
121
+ </span>
122
+ <Button
123
+ type="button"
124
+ variant="ghost"
125
+ className="size-8! p-0 absolute right-4"
126
+ onClick={handleClose}
142
127
  >
143
- <div className="flex-1 min-h-0 overflow-y-auto overscroll-contain lg:overflow-visible">
144
- <div className="flex flex-col items-center gap-4 lg:gap-8 px-4 lg:px-5 py-4 lg:py-6 pb-60 lg:pb-6">
145
- <p className="paragraph-small-regular text-gray-950 text-center max-w-full lg:max-w-[412px]">
146
- {translate.rich('common.account.twoFactor.instructions', {
147
- link: (chunks) => (
148
- <a
149
- href="https://support.google.com/accounts/answer/1066447"
150
- target="_blank"
151
- rel="noopener noreferrer"
152
- className="paragraph-small-medium underline"
153
- >
154
- {chunks}
155
- </a>
156
- ),
157
- })}
158
- </p>
128
+ <IconX size={18} />
129
+ </Button>
130
+ </div>
159
131
 
160
- <div className="border border-gray-200 rounded-lg overflow-hidden p-2 lg:p-3 flex items-center justify-center w-[136px] h-[136px] lg:w-[203px] lg:h-[203px]">
161
- {generateFailed ? (
162
- <button
163
- type="button"
164
- onClick={() => retryGenerate()}
165
- className="flex flex-col items-center gap-1.5 text-center"
132
+ <form
133
+ className="flex-1 min-h-0 flex flex-col"
134
+ onSubmit={(e) => {
135
+ e.preventDefault();
136
+ if (isCodeComplete) handleSubmit();
137
+ }}
138
+ >
139
+ <div className="flex-1 min-h-0 overflow-y-auto overscroll-contain lg:overflow-visible">
140
+ <div className="flex flex-col items-center gap-4 lg:gap-8 px-4 lg:px-5 py-4 lg:py-6 pb-60 lg:pb-6">
141
+ <p className="paragraph-small-regular text-gray-950 text-center max-w-full lg:max-w-[412px]">
142
+ {translate.rich('common.account.twoFactor.instructions', {
143
+ link: (chunks) => (
144
+ <a
145
+ href="https://support.google.com/accounts/answer/1066447"
146
+ target="_blank"
147
+ rel="noopener noreferrer"
148
+ className="paragraph-small-medium underline"
166
149
  >
167
- <IconRefresh size={20} className="text-gray-400" />
168
- <span className="paragraph-xsmall-medium text-gray-500">
169
- {translate('common.account.twoFactor.retry')}
170
- </span>
171
- </button>
172
- ) : isGenerating || !qrcode ? (
173
- <div className="skeleton w-full h-full rounded" />
174
- ) : (
175
- // eslint-disable-next-line @next/next/no-img-element
176
- <img
177
- src={qrcode}
178
- alt={translate('common.account.twoFactor.qrAlt')}
179
- className="w-full h-full"
180
- />
181
- )}
182
- </div>
150
+ {chunks}
151
+ </a>
152
+ ),
153
+ })}
154
+ </p>
183
155
 
184
- <div className="flex items-center gap-3 w-full">
185
- <Separator className="flex-1" />
186
- <span className="paragraph-xsmall-medium text-gray-500 opacity-80 whitespace-nowrap">
187
- {translate('common.account.twoFactor.pasteDigits')}
188
- </span>
189
- <Separator className="flex-1" />
190
- </div>
156
+ <div className="border border-gray-200 rounded-lg overflow-hidden p-2 lg:p-3 flex items-center justify-center w-[136px] h-[136px] lg:w-[203px] lg:h-[203px]">
157
+ {generateFailed ? (
158
+ <button
159
+ type="button"
160
+ onClick={() => retryGenerate()}
161
+ className="flex flex-col items-center gap-1.5 text-center"
162
+ >
163
+ <IconRefresh size={20} className="text-gray-400" />
164
+ <span className="paragraph-xsmall-medium text-gray-500">
165
+ {translate('common.account.twoFactor.retry')}
166
+ </span>
167
+ </button>
168
+ ) : isGenerating || !qrcode ? (
169
+ <div className="skeleton w-full h-full rounded" />
170
+ ) : (
171
+ // eslint-disable-next-line @next/next/no-img-element
172
+ <img
173
+ src={qrcode}
174
+ alt={translate('common.account.twoFactor.qrAlt')}
175
+ className="w-full h-full"
176
+ />
177
+ )}
178
+ </div>
191
179
 
192
- <div className="scroll-mt-20">
193
- <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}>
194
- <InputOTPGroup className="gap-2">
195
- {Array.from({ length: 6 }).map((_, i) => (
196
- <InputOTPSlot
197
- key={i}
198
- index={i}
199
- className="w-11! lg:w-12! h-13! lg:h-14! rounded-lg! text-lg border-gray-200"
200
- />
201
- ))}
202
- </InputOTPGroup>
203
- </InputOTP>
204
- </div>
180
+ <div className="flex items-center gap-3 w-full">
181
+ <Separator className="flex-1" />
182
+ <span className="paragraph-xsmall-medium text-gray-500 opacity-80 whitespace-nowrap">
183
+ {translate('common.account.twoFactor.pasteDigits')}
184
+ </span>
185
+ <Separator className="flex-1" />
205
186
  </div>
206
- </div>
207
187
 
208
- <div className="shrink-0 flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between gap-2 bg-white">
209
- <Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
210
- {translate('common.actions.cancel')}
211
- </Button>
212
- <Button type="submit" className="h-10!" disabled={!isCodeComplete || isConfirming}>
213
- {isConfirming
214
- ? translate('common.account.twoFactor.activating')
215
- : translate('common.account.twoFactor.activate')}
216
- </Button>
188
+ <div className="scroll-mt-20">
189
+ <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS} value={code} onChange={setCode}>
190
+ <InputOTPGroup className="gap-2">
191
+ {Array.from({ length: 6 }).map((_, i) => (
192
+ <InputOTPSlot
193
+ key={i}
194
+ index={i}
195
+ className="w-11! lg:w-12! h-13! lg:h-14! rounded-lg! text-lg border-gray-200"
196
+ />
197
+ ))}
198
+ </InputOTPGroup>
199
+ </InputOTP>
200
+ </div>
217
201
  </div>
218
- </form>
219
- </DialogContent>
220
- </Dialog>
221
- </DialogLayer>
202
+ </div>
203
+
204
+ <div className="shrink-0 flex items-center p-4 lg:p-5 border-t border-gray-200 justify-between gap-2 bg-white">
205
+ <Button variant="secondary" className="h-10!" type="button" onClick={handleClose}>
206
+ {translate('common.actions.cancel')}
207
+ </Button>
208
+ <Button type="submit" className="h-10!" disabled={!isCodeComplete || isConfirming}>
209
+ {isConfirming
210
+ ? translate('common.account.twoFactor.activating')
211
+ : translate('common.account.twoFactor.activate')}
212
+ </Button>
213
+ </div>
214
+ </form>
215
+ </DialogContent>
216
+ </Dialog>
222
217
  );
223
218
  }
@@ -20,7 +20,6 @@ import { useUpdateAccountUser } from '../../../modules/accounts/hooks/useAccount
20
20
  import { GENDER_OPTIONS } from '../constants';
21
21
  import { ChangePhoneModal } from './ChangePhoneModal';
22
22
  import { ChangeEmailModal } from './ChangeEmailModal';
23
- import { DialogLayer } from '../../ui/overlay/layers';
24
23
 
25
24
  interface MyProfileSectionProps {
26
25
  onClose: () => void;
@@ -270,11 +269,8 @@ export function MyProfileSection({ onClose, storageUrl }: MyProfileSectionProps)
270
269
  </div>
271
270
  </form>
272
271
 
273
- {/* Abrem por cima desta secao, mas sao declarados como irmaos dela. */}
274
- <DialogLayer>
275
- <ChangePhoneModal open={changePhoneOpen} onClose={() => setChangePhoneOpen(false)} />
276
- <ChangeEmailModal open={changeEmailOpen} onClose={() => setChangeEmailOpen(false)} />
277
- </DialogLayer>
272
+ <ChangePhoneModal open={changePhoneOpen} onClose={() => setChangePhoneOpen(false)} />
273
+ <ChangeEmailModal open={changeEmailOpen} onClose={() => setChangeEmailOpen(false)} />
278
274
  </>
279
275
  );
280
276
  }
@@ -201,12 +201,7 @@ export function UsersSelectorPopover({
201
201
  />
202
202
  </div>
203
203
  </TooltipTrigger>
204
- {/* Continua na mao: este tooltip nasce dentro de um
205
- `PopoverContent`, e a escala de faixas so modela
206
- aninhamento de modal. Sem o z explicito o tooltip
207
- fica na faixa do popover que o hospeda e some
208
- atras dele. */}
209
- <TooltipContent className="z-[1002]">
204
+ <TooltipContent>
210
205
  {inProject ? translate('common.layout.usersSelector.removeFromProject') : translate('common.layout.usersSelector.addToProject')}
211
206
  </TooltipContent>
212
207
  </Tooltip>
@@ -1,8 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { ComponentType, useContext } from 'react';
3
+ import { ComponentType } from 'react';
4
4
  import { useModalManager } from '../../store/useModalManager';
5
- import { DialogDepthContext } from '../ui/overlay/layers';
6
5
 
7
6
  interface ModalManagerProps {
8
7
  registry: Record<string, ComponentType>;
@@ -10,13 +9,12 @@ interface ModalManagerProps {
10
9
 
11
10
  export function ModalManager({ registry }: ModalManagerProps) {
12
11
  const { modalStack } = useModalManager();
13
- const depth = useContext(DialogDepthContext);
14
12
 
15
13
  if (modalStack.length === 0) return null;
16
14
 
17
15
  return (
18
16
  <>
19
- {modalStack.map((modal, index) => {
17
+ {modalStack.map((modal) => {
20
18
  const ModalComponent = registry[modal.key];
21
19
 
22
20
  if (!ModalComponent) {
@@ -24,11 +22,7 @@ export function ModalManager({ registry }: ModalManagerProps) {
24
22
  return null;
25
23
  }
26
24
 
27
- return (
28
- <DialogDepthContext.Provider value={depth + index} key={modal.key}>
29
- <ModalComponent />
30
- </DialogDepthContext.Provider>
31
- );
25
+ return <ModalComponent key={modal.key} />;
32
26
  })}
33
27
  </>
34
28
  );
@@ -26,7 +26,6 @@ import { readOfferStageCookie, writeOfferStageCookie } from '../../../../modules
26
26
  import { useAiCreditsOfferModal } from '../../../../store/useAiCreditsOfferModal';
27
27
  import { useModalManager } from '../../../../store/useModalManager';
28
28
  import { LoseOfferDialog } from './components/LoseOfferDialog';
29
- import { DialogLayer } from '../../../ui/overlay/layers';
30
29
  import { OfferIllustration } from './components/OfferIllustration';
31
30
  import { OfferPaymentField } from './components/OfferPaymentField';
32
31
 
@@ -389,17 +388,14 @@ export default function AiCreditsOfferModal() {
389
388
  </DialogContent>
390
389
  </Dialog>
391
390
 
392
- {/* Irmao do `Dialog` acima, entao nasceria na mesma faixa de z. */}
393
- <DialogLayer>
394
- <LoseOfferDialog
395
- open={confirmingExit}
396
- discountLabel={discountLabel}
397
- creditsLabel={creditsLabel}
398
- fullPriceLabel={fullPrice != null ? formatCurrencyNumber(fullPrice) : ''}
399
- onKeep={() => setConfirmingExit(false)}
400
- onLose={dismiss}
401
- />
402
- </DialogLayer>
391
+ <LoseOfferDialog
392
+ open={confirmingExit}
393
+ discountLabel={discountLabel}
394
+ creditsLabel={creditsLabel}
395
+ fullPriceLabel={fullPrice != null ? formatCurrencyNumber(fullPrice) : ''}
396
+ onKeep={() => setConfirmingExit(false)}
397
+ onLose={dismiss}
398
+ />
403
399
  </>
404
400
  );
405
401
  }
@@ -4,21 +4,12 @@ import * as React from "react";
4
4
  import * as DialogPrimitive from "@radix-ui/react-dialog";
5
5
  import { IconX } from '@tabler/icons-react';
6
6
  import { cn } from "../../../infra/utils/clsx";
7
- import { DialogDepthContext, useDialogLayer } from "./layers";
8
-
9
- // Cada `Dialog` aninhado sobe uma faixa de z-index, para que o overlay do modal
10
- // de cima cubra o conteudo do modal de baixo. A escala (e os dropdowns e
11
- // tooltips que precisam acompanhar) vive em `./layers`.
7
+ import { OverlayLayerContext, useDialogLayer, useOverlayLayer } from "./layers";
12
8
 
13
9
  function Dialog({
14
10
  ...props
15
11
  }: React.ComponentProps<typeof DialogPrimitive.Root>) {
16
- const depth = React.useContext(DialogDepthContext);
17
- return (
18
- <DialogDepthContext.Provider value={depth + 1}>
19
- <DialogPrimitive.Root data-slot="dialog" {...props} />
20
- </DialogDepthContext.Provider>
21
- );
12
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
22
13
  }
23
14
 
24
15
  function DialogTrigger({
@@ -64,40 +55,43 @@ function DialogContent({
64
55
  overlayClassName,
65
56
  hideOverlay = false,
66
57
  ...props
67
- }: React.ComponentProps<typeof DialogPrimitive.Content> & {
58
+ }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
68
59
  showCloseButton?: boolean;
69
60
  overlayClassName?: string;
70
61
  hideOverlay?: boolean;
71
62
  }) {
72
- const layer = useDialogLayer();
63
+ const { layer, presenceRef } = useOverlayLayer();
73
64
  return (
74
- <DialogPortal data-slot="dialog-portal">
75
- {!hideOverlay && <DialogOverlay className={overlayClassName} />}
76
- <DialogPrimitive.Content
77
- data-slot="dialog-content"
78
- className={cn(
79
- "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
80
- layer.content,
81
- className,
82
- )}
83
- {...props}
84
- >
85
- {children}
86
- {showCloseButton && (
87
- <div className="absolute top-0.5 right-0">
88
- <div className="p-4">
89
- <DialogPrimitive.Close
90
- data-slot="dialog-close"
91
- className="hover:cursor-pointer flex size-8 items-center justify-center rounded-lg p-2 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-950 focus:outline-none"
92
- >
93
- <IconX className="size-[18px]" />
94
- <span className="sr-only">Close</span>
95
- </DialogPrimitive.Close>
65
+ <OverlayLayerContext.Provider value={layer}>
66
+ <DialogPortal data-slot="dialog-portal">
67
+ {!hideOverlay && <DialogOverlay className={overlayClassName} />}
68
+ <DialogPrimitive.Content
69
+ ref={presenceRef}
70
+ data-slot="dialog-content"
71
+ className={cn(
72
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
73
+ layer.content,
74
+ className,
75
+ )}
76
+ {...props}
77
+ >
78
+ {children}
79
+ {showCloseButton && (
80
+ <div className="absolute top-0.5 right-0">
81
+ <div className="p-4">
82
+ <DialogPrimitive.Close
83
+ data-slot="dialog-close"
84
+ className="hover:cursor-pointer flex size-8 items-center justify-center rounded-lg p-2 text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-950 focus:outline-none"
85
+ >
86
+ <IconX className="size-[18px]" />
87
+ <span className="sr-only">Close</span>
88
+ </DialogPrimitive.Close>
89
+ </div>
96
90
  </div>
97
- </div>
98
- )}
99
- </DialogPrimitive.Content>
100
- </DialogPortal>
91
+ )}
92
+ </DialogPrimitive.Content>
93
+ </DialogPortal>
94
+ </OverlayLayerContext.Provider>
101
95
  );
102
96
  }
103
97
 
@@ -5,7 +5,7 @@
5
5
  import * as React from "react"
6
6
  import * as PopoverPrimitive from "@radix-ui/react-popover"
7
7
  import { cn } from "../../../infra/utils/clsx"
8
- import { useDialogLayer } from "./layers"
8
+ import { OVERLAY_LAYERS, OverlayLayerContext, ROOT_LAYER, useDialogLayer } from "./layers"
9
9
 
10
10
  function Popover({
11
11
  ...props
@@ -25,22 +25,23 @@ function PopoverContent({
25
25
  sideOffset = 4,
26
26
  ...props
27
27
  }: React.ComponentProps<typeof PopoverPrimitive.Content>) {
28
- // Portaliza para o body, entao disputa z com o conteudo do modal que o abriu.
29
28
  const layer = useDialogLayer()
30
29
  return (
31
- <PopoverPrimitive.Portal>
32
- <PopoverPrimitive.Content
33
- data-slot="popover-content"
34
- align={align}
35
- sideOffset={sideOffset}
36
- className={cn(
37
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
38
- layer.popover,
39
- className
40
- )}
41
- {...props}
42
- />
43
- </PopoverPrimitive.Portal>
30
+ <OverlayLayerContext.Provider value={layer === ROOT_LAYER ? OVERLAY_LAYERS[0] : layer}>
31
+ <PopoverPrimitive.Portal>
32
+ <PopoverPrimitive.Content
33
+ data-slot="popover-content"
34
+ align={align}
35
+ sideOffset={sideOffset}
36
+ className={cn(
37
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
38
+ layer.popover,
39
+ className
40
+ )}
41
+ {...props}
42
+ />
43
+ </PopoverPrimitive.Portal>
44
+ </OverlayLayerContext.Provider>
44
45
  )
45
46
  }
46
47