@oxyhq/bloom 0.66.0 → 0.68.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/lib/commonjs/dialog/Dialog.web.js +31 -13
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/toast/Toaster.js +5 -0
- package/lib/commonjs/toast/Toaster.js.map +1 -1
- package/lib/commonjs/toast/use-single-outlet-guard.js +72 -0
- package/lib/commonjs/toast/use-single-outlet-guard.js.map +1 -0
- package/lib/module/dialog/Dialog.web.js +31 -12
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/toast/Toaster.js +5 -0
- package/lib/module/toast/Toaster.js.map +1 -1
- package/lib/module/toast/use-single-outlet-guard.js +65 -0
- package/lib/module/toast/use-single-outlet-guard.js.map +1 -0
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts +1 -3
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/toast/Toaster.d.ts.map +1 -1
- package/lib/typescript/commonjs/toast/use-single-outlet-guard.d.ts +9 -0
- package/lib/typescript/commonjs/toast/use-single-outlet-guard.d.ts.map +1 -0
- package/lib/typescript/module/dialog/Dialog.web.d.ts +1 -3
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/toast/Toaster.d.ts.map +1 -1
- package/lib/typescript/module/toast/use-single-outlet-guard.d.ts +9 -0
- package/lib/typescript/module/toast/use-single-outlet-guard.d.ts.map +1 -0
- package/package.json +347 -87
- package/src/__tests__/Dialog.web.test.tsx +5 -2
- package/src/__tests__/backdrop-fade-form.test.ts +91 -0
- package/src/__tests__/exports-map-contract.test.ts +112 -0
- package/src/__tests__/toast-single-outlet-guard.test.tsx +176 -0
- package/src/dialog/Dialog.web.tsx +32 -10
- package/src/toast/Toaster.tsx +6 -0
- package/src/toast/use-single-outlet-guard.ts +72 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bloom-original — the dev-only guard against a SECOND toast outlet.
|
|
5
|
+
*
|
|
6
|
+
* Every `Toaster` subscribes to the ONE module-level `toastStore`, which has no
|
|
7
|
+
* notion of an owning outlet, so N mounted outlets each render the full row set:
|
|
8
|
+
* a toast appears N times. Nothing in the engine can dedupe that — the outlets
|
|
9
|
+
* are legitimate, independent subscribers — so the contract is "mount exactly
|
|
10
|
+
* one" and this is what enforces it.
|
|
11
|
+
*
|
|
12
|
+
* WHY A WARNING IS WORTH ITS WEIGHT: the copies are not visually separated, so
|
|
13
|
+
* the defect does not look like duplication. Two bare outlets take identical
|
|
14
|
+
* defaults and land pixel-identical; two outlets whose `offset` differs by a
|
|
15
|
+
* point land 1px apart. Only counting the rendered rows reveals it, which is not
|
|
16
|
+
* something anyone thinks to do — the reports this guard comes from all read as
|
|
17
|
+
* "the toast looks wrong", never as "there are two of them". Stacking is on by
|
|
18
|
+
* default, so a duplicate outlet now doubles the rows INSIDE a stack.
|
|
19
|
+
*
|
|
20
|
+
* The counter is decremented on unmount, so a remount, a route change that moves
|
|
21
|
+
* the outlet, Fast Refresh and React's StrictMode double-invoke (setup, cleanup,
|
|
22
|
+
* setup) all pass through a count of 1 and stay silent. The latch keeps the
|
|
23
|
+
* warning to exactly one per module lifetime rather than one per extra outlet,
|
|
24
|
+
* and — because StrictMode replays the setups — one per app, not two.
|
|
25
|
+
*
|
|
26
|
+
* Gated on `process.env.NODE_ENV`, the same mechanism as
|
|
27
|
+
* `content-panel/nesting-context.ts`: Metro and Vite/Rolldown both fold it
|
|
28
|
+
* statically, so production keeps the counter, the branch and the message out of
|
|
29
|
+
* the bundle entirely. Deliberately NOT `__DEV__`, which is a Metro global that a
|
|
30
|
+
* plain web bundler does not define. It only ever warns — a duplicate outlet
|
|
31
|
+
* renders a redundant toast, it does not break the app, so it must never throw.
|
|
32
|
+
*/
|
|
33
|
+
import * as React from 'react';
|
|
34
|
+
let mountedOutlets = 0;
|
|
35
|
+
let hasWarned = false;
|
|
36
|
+
export function useSingleOutletGuard() {
|
|
37
|
+
React.useEffect(() => {
|
|
38
|
+
if (process.env.NODE_ENV === 'production') {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
mountedOutlets += 1;
|
|
42
|
+
if (mountedOutlets > 1 && !hasWarned) {
|
|
43
|
+
hasWarned = true;
|
|
44
|
+
// Internal Bloom diagnostic: the consumer's tree is the only place this
|
|
45
|
+
// can be fixed, so it names the usual cause rather than just the symptom.
|
|
46
|
+
// eslint-disable-next-line no-console
|
|
47
|
+
console.warn(`[Bloom] Toaster: ${mountedOutlets} toast outlets are mounted, so every ` + 'toast renders once per outlet. The copies overlap almost exactly, so ' + 'this reads as a rendering glitch rather than as duplicate rows. Mount ' + "exactly one: @oxyhq/services' OxyProvider already renders a " + 'ToastOutlet, so an app that uses it must not render its own.');
|
|
48
|
+
}
|
|
49
|
+
return () => {
|
|
50
|
+
mountedOutlets -= 1;
|
|
51
|
+
};
|
|
52
|
+
}, []);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Test-only reset: both the counter and the one-shot latch are module state that
|
|
57
|
+
* outlives a render tree, so without this the first suite to mount two outlets
|
|
58
|
+
* would latch the warning and leave every later suite asserting against a guard
|
|
59
|
+
* that can no longer fire — passing whatever the implementation did.
|
|
60
|
+
*/
|
|
61
|
+
export function resetSingleOutletGuardForTests() {
|
|
62
|
+
mountedOutlets = 0;
|
|
63
|
+
hasWarned = false;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=use-single-outlet-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","mountedOutlets","hasWarned","useSingleOutletGuard","useEffect","process","env","NODE_ENV","console","warn","resetSingleOutletGuardForTests"],"sourceRoot":"../../../src","sources":["toast/use-single-outlet-guard.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,IAAIC,cAAc,GAAG,CAAC;AACtB,IAAIC,SAAS,GAAG,KAAK;AAErB,OAAO,SAASC,oBAAoBA,CAAA,EAAS;EAC3CH,KAAK,CAACI,SAAS,CAAC,MAAM;IACpB,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,EAAE;MACzC;IACF;IAEAN,cAAc,IAAI,CAAC;IACnB,IAAIA,cAAc,GAAG,CAAC,IAAI,CAACC,SAAS,EAAE;MACpCA,SAAS,GAAG,IAAI;MAChB;MACA;MACA;MACAM,OAAO,CAACC,IAAI,CACV,oBAAoBR,cAAc,uCAAuC,GACvE,uEAAuE,GACvE,wEAAwE,GACxE,8DAA8D,GAC9D,8DACJ,CAAC;IACH;IAEA,OAAO,MAAM;MACXA,cAAc,IAAI,CAAC;IACrB,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;AACR;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASS,8BAA8BA,CAAA,EAAS;EACrDT,cAAc,GAAG,CAAC;EAClBC,SAAS,GAAG,KAAK;AACnB","ignoreList":[]}
|
|
@@ -47,8 +47,6 @@ export declare function AutoMountedDialog({ title, description, actions, onResol
|
|
|
47
47
|
* injection is guarded by a unique style id.
|
|
48
48
|
*
|
|
49
49
|
* ```css
|
|
50
|
-
* @keyframes bloomDialogFadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
51
|
-
* @keyframes bloomDialogFadeOut { from { opacity: 1; } to { opacity: 0; } }
|
|
52
50
|
* @keyframes bloomDialogZoomFadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }
|
|
53
51
|
* @keyframes bloomDialogZoomFadeOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } }
|
|
54
52
|
* ```
|
|
@@ -57,5 +55,5 @@ export declare function AutoMountedDialog({ title, description, actions, onResol
|
|
|
57
55
|
* self-contained inline CSS transitions and need no keyframe injection. The
|
|
58
56
|
* `bottom` placement uses bloom's `BottomSheet` (reanimated) and needs none.
|
|
59
57
|
*/
|
|
60
|
-
export declare const BLOOM_DIALOG_CSS = "\n@keyframes
|
|
58
|
+
export declare const BLOOM_DIALOG_CSS = "\n@keyframes bloomDialogZoomFadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }\n@keyframes bloomDialogZoomFadeOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } }\n";
|
|
61
59
|
//# sourceMappingURL=Dialog.web.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.web.d.ts","sourceRoot":"","sources":["../../../../src/dialog/Dialog.web.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Dialog.web.d.ts","sourceRoot":"","sources":["../../../../src/dialog/Dialog.web.tsx"],"names":[],"mappings":"AA2CA,OAAO,EAOL,4BAA4B,EAK7B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,YAAY,EAGZ,WAAW,EACZ,MAAM,SAAS,CAAC;AAwDjB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,2CAazD;AAobD,OAAO,EAAE,4BAA4B,EAAE,CAAC;AAiPxC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,WAAW,EACX,OAAO,EACP,SAAS,GACV,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,2CAgBA;AAiCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,8PAG5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../../src/toast/Toaster.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAGV,YAAY,EAGb,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../../src/toast/Toaster.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAGV,YAAY,EAGb,MAAM,SAAS,CAAC;AA0BjB,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CA8M1C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function useSingleOutletGuard(): void;
|
|
2
|
+
/**
|
|
3
|
+
* Test-only reset: both the counter and the one-shot latch are module state that
|
|
4
|
+
* outlives a render tree, so without this the first suite to mount two outlets
|
|
5
|
+
* would latch the warning and leave every later suite asserting against a guard
|
|
6
|
+
* that can no longer fire — passing whatever the implementation did.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resetSingleOutletGuardForTests(): void;
|
|
9
|
+
//# sourceMappingURL=use-single-outlet-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-single-outlet-guard.d.ts","sourceRoot":"","sources":["../../../../src/toast/use-single-outlet-guard.ts"],"names":[],"mappings":"AAmCA,wBAAgB,oBAAoB,IAAI,IAAI,CAyB3C;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
|
|
@@ -47,8 +47,6 @@ export declare function AutoMountedDialog({ title, description, actions, onResol
|
|
|
47
47
|
* injection is guarded by a unique style id.
|
|
48
48
|
*
|
|
49
49
|
* ```css
|
|
50
|
-
* @keyframes bloomDialogFadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
51
|
-
* @keyframes bloomDialogFadeOut { from { opacity: 1; } to { opacity: 0; } }
|
|
52
50
|
* @keyframes bloomDialogZoomFadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }
|
|
53
51
|
* @keyframes bloomDialogZoomFadeOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } }
|
|
54
52
|
* ```
|
|
@@ -57,5 +55,5 @@ export declare function AutoMountedDialog({ title, description, actions, onResol
|
|
|
57
55
|
* self-contained inline CSS transitions and need no keyframe injection. The
|
|
58
56
|
* `bottom` placement uses bloom's `BottomSheet` (reanimated) and needs none.
|
|
59
57
|
*/
|
|
60
|
-
export declare const BLOOM_DIALOG_CSS = "\n@keyframes
|
|
58
|
+
export declare const BLOOM_DIALOG_CSS = "\n@keyframes bloomDialogZoomFadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }\n@keyframes bloomDialogZoomFadeOut { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } }\n";
|
|
61
59
|
//# sourceMappingURL=Dialog.web.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.web.d.ts","sourceRoot":"","sources":["../../../../src/dialog/Dialog.web.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Dialog.web.d.ts","sourceRoot":"","sources":["../../../../src/dialog/Dialog.web.tsx"],"names":[],"mappings":"AA2CA,OAAO,EAOL,4BAA4B,EAK7B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,YAAY,EAGZ,WAAW,EACZ,MAAM,SAAS,CAAC;AAwDjB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,2CAazD;AAobD,OAAO,EAAE,4BAA4B,EAAE,CAAC;AAiPxC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,WAAW,EACX,OAAO,EACP,SAAS,GACV,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,2CAgBA;AAiCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,8PAG5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../../src/toast/Toaster.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAGV,YAAY,EAGb,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../../src/toast/Toaster.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAGV,YAAY,EAGb,MAAM,SAAS,CAAC;AA0BjB,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CA8M1C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function useSingleOutletGuard(): void;
|
|
2
|
+
/**
|
|
3
|
+
* Test-only reset: both the counter and the one-shot latch are module state that
|
|
4
|
+
* outlives a render tree, so without this the first suite to mount two outlets
|
|
5
|
+
* would latch the warning and leave every later suite asserting against a guard
|
|
6
|
+
* that can no longer fire — passing whatever the implementation did.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resetSingleOutletGuardForTests(): void;
|
|
9
|
+
//# sourceMappingURL=use-single-outlet-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-single-outlet-guard.d.ts","sourceRoot":"","sources":["../../../../src/toast/use-single-outlet-guard.ts"],"names":[],"mappings":"AAmCA,wBAAgB,oBAAoB,IAAI,IAAI,CAyB3C;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
|