@ankhorage/surface 0.1.8 → 0.1.9
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/CHANGELOG.md +10 -0
- package/dist/internal/overlay/OverlayProvider.d.ts.map +1 -1
- package/dist/internal/overlay/OverlayProvider.js +15 -9
- package/dist/internal/overlay/OverlayProvider.js.map +1 -1
- package/dist/internal/overlay/Portal.d.ts.map +1 -1
- package/dist/internal/overlay/Portal.js +18 -9
- package/dist/internal/overlay/Portal.js.map +1 -1
- package/dist/internal/overlay/useOverlayStack.d.ts +6 -2
- package/dist/internal/overlay/useOverlayStack.d.ts.map +1 -1
- package/dist/internal/overlay/useOverlayStack.js +4 -0
- package/dist/internal/overlay/useOverlayStack.js.map +1 -1
- package/package.json +1 -1
- package/src/internal/overlay/OverlayProvider.tsx +41 -30
- package/src/internal/overlay/Portal.tsx +21 -10
- package/src/internal/overlay/useOverlayStack.ts +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @ankhorage/surface
|
|
2
2
|
|
|
3
|
+
## 0.1.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f454c88: Fix infinite render loop in overlay portal
|
|
8
|
+
|
|
9
|
+
Splits overlay context into state and actions to prevent Portal from
|
|
10
|
+
re-registering overlays on every render. Fixes "Maximum update depth exceeded"
|
|
11
|
+
when opening Modal and Drawer.
|
|
12
|
+
|
|
3
13
|
## 0.1.8
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverlayProvider.d.ts","sourceRoot":"","sources":["../../../src/internal/overlay/OverlayProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"OverlayProvider.d.ts","sourceRoot":"","sources":["../../../src/internal/overlay/OverlayProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,qBAwE1E"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
|
-
import { createOverlayEntry, OverlayStackContext, sortOverlayEntries, } from './useOverlayStack';
|
|
3
|
+
import { createOverlayEntry, OverlayStackActionsContext, OverlayStackContext, sortOverlayEntries, } from './useOverlayStack';
|
|
4
4
|
export function OverlayProvider({ children }) {
|
|
5
5
|
const orderRef = React.useRef(0);
|
|
6
6
|
const [overlays, setOverlays] = React.useState([]);
|
|
@@ -17,21 +17,26 @@ export function OverlayProvider({ children }) {
|
|
|
17
17
|
const removeOverlay = React.useCallback((id) => {
|
|
18
18
|
setOverlays((current) => current.filter((entry) => entry.id !== id));
|
|
19
19
|
}, []);
|
|
20
|
+
const actions = React.useMemo(() => ({
|
|
21
|
+
removeOverlay,
|
|
22
|
+
setOverlay,
|
|
23
|
+
}), [removeOverlay, setOverlay]);
|
|
20
24
|
const value = React.useMemo(() => ({
|
|
21
25
|
overlays,
|
|
22
26
|
removeOverlay,
|
|
23
27
|
setOverlay,
|
|
24
28
|
}), [overlays, removeOverlay, setOverlay]);
|
|
25
|
-
return (<
|
|
26
|
-
{
|
|
27
|
-
|
|
29
|
+
return (<OverlayStackActionsContext.Provider value={actions}>
|
|
30
|
+
<OverlayStackContext.Provider value={value}>
|
|
31
|
+
{children}
|
|
32
|
+
<View pointerEvents="box-none" style={{
|
|
28
33
|
bottom: 0,
|
|
29
34
|
left: 0,
|
|
30
35
|
position: 'absolute',
|
|
31
36
|
right: 0,
|
|
32
37
|
top: 0,
|
|
33
38
|
}}>
|
|
34
|
-
|
|
39
|
+
{overlays.map((overlay) => (<View key={overlay.id} pointerEvents="box-none" style={{
|
|
35
40
|
bottom: 0,
|
|
36
41
|
left: 0,
|
|
37
42
|
position: 'absolute',
|
|
@@ -39,9 +44,10 @@ export function OverlayProvider({ children }) {
|
|
|
39
44
|
top: 0,
|
|
40
45
|
zIndex: overlay.zIndex,
|
|
41
46
|
}}>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
{overlay.node}
|
|
48
|
+
</View>))}
|
|
49
|
+
</View>
|
|
50
|
+
</OverlayStackContext.Provider>
|
|
51
|
+
</OverlayStackActionsContext.Provider>);
|
|
46
52
|
}
|
|
47
53
|
//# sourceMappingURL=OverlayProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverlayProvider.js","sourceRoot":"","sources":["../../../src/internal/overlay/OverlayProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,OAAO,EACL,kBAAkB,EAGlB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAiC;IACzE,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAiB,EAAE,CAAC,CAAC;IAEnE,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,EAAU,EAAE,UAA6B,EAAE,EAAE;QACjF,WAAW,CAAC,CAAC,OAAO,EAAE,EAAE;YACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1D,MAAM,SAAS,GAAG,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;YAE5F,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;YACrD,CAAC;YAED,OAAO,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3F,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QACrD,WAAW,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ;QACR,aAAa;QACb,UAAU;KACX,CAAC,EACF,CAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,CACtC,CAAC;IAEF,OAAO,CACL,CAAC,mBAAmB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CACzC;
|
|
1
|
+
{"version":3,"file":"OverlayProvider.js","sourceRoot":"","sources":["../../../src/internal/overlay/OverlayProvider.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { View } from 'react-native';\n\nimport {\n createOverlayEntry,\n type OverlayDescriptor,\n type OverlayEntry,\n OverlayStackActionsContext,\n OverlayStackContext,\n sortOverlayEntries,\n} from './useOverlayStack';\n\nexport function OverlayProvider({ children }: { children: React.ReactNode }) {\n const orderRef = React.useRef(0);\n const [overlays, setOverlays] = React.useState<OverlayEntry[]>([]);\n\n const setOverlay = React.useCallback((id: string, descriptor: OverlayDescriptor) => {\n setOverlays((current) => {\n const existing = current.find((entry) => entry.id === id);\n const nextEntry = createOverlayEntry(id, existing?.order ?? orderRef.current++, descriptor);\n\n if (!existing) {\n return sortOverlayEntries([...current, nextEntry]);\n }\n\n return sortOverlayEntries(current.map((entry) => (entry.id === id ? nextEntry : entry)));\n });\n }, []);\n\n const removeOverlay = React.useCallback((id: string) => {\n setOverlays((current) => current.filter((entry) => entry.id !== id));\n }, []);\n\n const actions = React.useMemo(\n () => ({\n removeOverlay,\n setOverlay,\n }),\n [removeOverlay, setOverlay],\n );\n\n const value = React.useMemo(\n () => ({\n overlays,\n removeOverlay,\n setOverlay,\n }),\n [overlays, removeOverlay, setOverlay],\n );\n\n return (\n <OverlayStackActionsContext.Provider value={actions}>\n <OverlayStackContext.Provider value={value}>\n {children}\n <View\n pointerEvents=\"box-none\"\n style={{\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n }}\n >\n {overlays.map((overlay) => (\n <View\n key={overlay.id}\n pointerEvents=\"box-none\"\n style={{\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n zIndex: overlay.zIndex,\n }}\n >\n {overlay.node}\n </View>\n ))}\n </View>\n </OverlayStackContext.Provider>\n </OverlayStackActionsContext.Provider>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Portal.d.ts","sourceRoot":"","sources":["../../../src/internal/overlay/Portal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAKtE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAe,EAAE,OAAc,EAAE,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"Portal.d.ts","sourceRoot":"","sources":["../../../src/internal/overlay/Portal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAKtE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAe,EAAE,OAAc,EAAE,EAAE,WAAW,4BAmChF"}
|
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useOverlayStackActions } from './useOverlayStack';
|
|
3
3
|
let portalCounter = 0;
|
|
4
4
|
export function Portal({ children, layer = 'modal', visible = true }) {
|
|
5
|
-
const
|
|
5
|
+
const overlayActions = useOverlayStackActions();
|
|
6
6
|
const idRef = React.useRef(`surface-portal-${portalCounter++}`);
|
|
7
7
|
React.useEffect(() => {
|
|
8
|
-
if (!
|
|
8
|
+
if (!overlayActions || !visible) {
|
|
9
9
|
return undefined;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
return () => {
|
|
12
|
+
overlayActions.removeOverlay(idRef.current);
|
|
13
|
+
};
|
|
14
|
+
}, [overlayActions, visible]);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
if (!overlayActions || !visible) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (children === undefined || children === null) {
|
|
20
|
+
overlayActions.removeOverlay(idRef.current);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
overlayActions.setOverlay(idRef.current, {
|
|
12
24
|
layer,
|
|
13
25
|
node: children,
|
|
14
26
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
-
}, [children, layer, overlayStack, visible]);
|
|
19
|
-
if (!overlayStack) {
|
|
27
|
+
}, [children, layer, overlayActions, visible]);
|
|
28
|
+
if (!overlayActions) {
|
|
20
29
|
return visible ? <>{children}</> : null;
|
|
21
30
|
}
|
|
22
31
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Portal.js","sourceRoot":"","sources":["../../../src/internal/overlay/Portal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Portal.js","sourceRoot":"","sources":["../../../src/internal/overlay/Portal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,IAAI,aAAa,GAAG,CAAC,CAAC;AAQtB,MAAM,UAAU,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,IAAI,EAAe;IAC/E,MAAM,cAAc,GAAG,sBAAsB,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,kBAAkB,aAAa,EAAE,EAAE,CAAC,CAAC;IAEhE,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,GAAG,EAAE;YACV,cAAc,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAE9B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAChD,cAAc,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE;YACvC,KAAK;YACL,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;IAE/C,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import React from 'react';\n\nimport type { OverlayLayer } from '../resolvers/resolveOverlayZIndex';\nimport { useOverlayStackActions } from './useOverlayStack';\n\nlet portalCounter = 0;\n\nexport interface PortalProps {\n children?: React.ReactNode;\n layer?: OverlayLayer;\n visible?: boolean;\n}\n\nexport function Portal({ children, layer = 'modal', visible = true }: PortalProps) {\n const overlayActions = useOverlayStackActions();\n const idRef = React.useRef(`surface-portal-${portalCounter++}`);\n\n React.useEffect(() => {\n if (!overlayActions || !visible) {\n return undefined;\n }\n\n return () => {\n overlayActions.removeOverlay(idRef.current);\n };\n }, [overlayActions, visible]);\n\n React.useEffect(() => {\n if (!overlayActions || !visible) {\n return;\n }\n\n if (children === undefined || children === null) {\n overlayActions.removeOverlay(idRef.current);\n return;\n }\n\n overlayActions.setOverlay(idRef.current, {\n layer,\n node: children,\n });\n }, [children, layer, overlayActions, visible]);\n\n if (!overlayActions) {\n return visible ? <>{children}</> : null;\n }\n\n return null;\n}\n"]}
|
|
@@ -11,13 +11,17 @@ export interface OverlayDescriptor {
|
|
|
11
11
|
layer: OverlayLayer;
|
|
12
12
|
node: React.ReactNode;
|
|
13
13
|
}
|
|
14
|
-
export interface
|
|
15
|
-
overlays: OverlayEntry[];
|
|
14
|
+
export interface OverlayStackActions {
|
|
16
15
|
setOverlay: (id: string, overlay: OverlayDescriptor) => void;
|
|
17
16
|
removeOverlay: (id: string) => void;
|
|
18
17
|
}
|
|
18
|
+
export interface OverlayStackRuntime extends OverlayStackActions {
|
|
19
|
+
overlays: OverlayEntry[];
|
|
20
|
+
}
|
|
19
21
|
export declare function sortOverlayEntries(entries: OverlayEntry[]): OverlayEntry[];
|
|
20
22
|
export declare const OverlayStackContext: React.Context<OverlayStackRuntime | null>;
|
|
23
|
+
export declare const OverlayStackActionsContext: React.Context<OverlayStackActions | null>;
|
|
21
24
|
export declare function useOverlayStack(): OverlayStackRuntime | null;
|
|
25
|
+
export declare function useOverlayStackActions(): OverlayStackActions | null;
|
|
22
26
|
export declare function createOverlayEntry(id: string, order: number, descriptor: OverlayDescriptor): OverlayEntry;
|
|
23
27
|
//# sourceMappingURL=useOverlayStack.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOverlayStack.d.ts","sourceRoot":"","sources":["../../../src/internal/overlay/useOverlayStack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,KAAK,YAAY,EAAwB,MAAM,mCAAmC,CAAC;AAE5F,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,
|
|
1
|
+
{"version":3,"file":"useOverlayStack.d.ts","sourceRoot":"","sources":["../../../src/internal/overlay/useOverlayStack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,KAAK,YAAY,EAAwB,MAAM,mCAAmC,CAAC;AAE5F,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC7D,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAiB1E;AAED,eAAO,MAAM,mBAAmB,2CAAwD,CAAC;AAEzF,eAAO,MAAM,0BAA0B,2CAAwD,CAAC;AAEhG,wBAAgB,eAAe,IAAI,mBAAmB,GAAG,IAAI,CAE5D;AAED,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,IAAI,CAEnE;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,iBAAiB,GAC5B,YAAY,CAQd"}
|
|
@@ -15,9 +15,13 @@ export function sortOverlayEntries(entries) {
|
|
|
15
15
|
return normalizedEntries.sort((left, right) => left.zIndex === right.zIndex ? left.order - right.order : left.zIndex - right.zIndex);
|
|
16
16
|
}
|
|
17
17
|
export const OverlayStackContext = React.createContext(null);
|
|
18
|
+
export const OverlayStackActionsContext = React.createContext(null);
|
|
18
19
|
export function useOverlayStack() {
|
|
19
20
|
return React.useContext(OverlayStackContext);
|
|
20
21
|
}
|
|
22
|
+
export function useOverlayStackActions() {
|
|
23
|
+
return React.useContext(OverlayStackActionsContext);
|
|
24
|
+
}
|
|
21
25
|
export function createOverlayEntry(id, order, descriptor) {
|
|
22
26
|
return {
|
|
23
27
|
id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOverlayStack.js","sourceRoot":"","sources":["../../../src/internal/overlay/useOverlayStack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAqB,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"useOverlayStack.js","sourceRoot":"","sources":["../../../src/internal/overlay/useOverlayStack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAqB,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAwB5F,MAAM,UAAU,kBAAkB,CAAC,OAAuB;IACxD,MAAM,cAAc,GAA0C,EAAE,CAAC;IACjE,MAAM,iBAAiB,GAAG,CAAC,GAAG,OAAO,CAAC;SACnC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;SAC/C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpD,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC;QAE7C,OAAO;YACL,GAAG,KAAK;YACR,MAAM,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC;SACtD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAC5C,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CACrF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC,aAAa,CAA6B,IAAI,CAAC,CAAC;AAEzF,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,CAAC,aAAa,CAA6B,IAAI,CAAC,CAAC;AAEhG,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,KAAK,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,EAAU,EACV,KAAa,EACb,UAA6B;IAE7B,OAAO;QACL,EAAE;QACF,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,IAAI,EAAE,UAAU,CAAC,IAAI;QACrB,KAAK;QACL,MAAM,EAAE,oBAAoB,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;KAClD,CAAC;AACJ,CAAC","sourcesContent":["import React from 'react';\n\nimport { type OverlayLayer, resolveOverlayZIndex } from '../resolvers/resolveOverlayZIndex';\n\nexport interface OverlayEntry {\n id: string;\n layer: OverlayLayer;\n node: React.ReactNode;\n order: number;\n zIndex: number;\n}\n\nexport interface OverlayDescriptor {\n layer: OverlayLayer;\n node: React.ReactNode;\n}\n\nexport interface OverlayStackActions {\n setOverlay: (id: string, overlay: OverlayDescriptor) => void;\n removeOverlay: (id: string) => void;\n}\n\nexport interface OverlayStackRuntime extends OverlayStackActions {\n overlays: OverlayEntry[];\n}\n\nexport function sortOverlayEntries(entries: OverlayEntry[]): OverlayEntry[] {\n const perLayerCounts: Partial<Record<OverlayLayer, number>> = {};\n const normalizedEntries = [...entries]\n .sort((left, right) => left.order - right.order)\n .map((entry) => {\n const stackIndex = perLayerCounts[entry.layer] ?? 0;\n perLayerCounts[entry.layer] = stackIndex + 1;\n\n return {\n ...entry,\n zIndex: resolveOverlayZIndex(entry.layer, stackIndex),\n };\n });\n\n return normalizedEntries.sort((left, right) =>\n left.zIndex === right.zIndex ? left.order - right.order : left.zIndex - right.zIndex,\n );\n}\n\nexport const OverlayStackContext = React.createContext<OverlayStackRuntime | null>(null);\n\nexport const OverlayStackActionsContext = React.createContext<OverlayStackActions | null>(null);\n\nexport function useOverlayStack(): OverlayStackRuntime | null {\n return React.useContext(OverlayStackContext);\n}\n\nexport function useOverlayStackActions(): OverlayStackActions | null {\n return React.useContext(OverlayStackActionsContext);\n}\n\nexport function createOverlayEntry(\n id: string,\n order: number,\n descriptor: OverlayDescriptor,\n): OverlayEntry {\n return {\n id,\n layer: descriptor.layer,\n node: descriptor.node,\n order,\n zIndex: resolveOverlayZIndex(descriptor.layer, 0),\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
createOverlayEntry,
|
|
6
6
|
type OverlayDescriptor,
|
|
7
7
|
type OverlayEntry,
|
|
8
|
+
OverlayStackActionsContext,
|
|
8
9
|
OverlayStackContext,
|
|
9
10
|
sortOverlayEntries,
|
|
10
11
|
} from './useOverlayStack';
|
|
@@ -30,6 +31,14 @@ export function OverlayProvider({ children }: { children: React.ReactNode }) {
|
|
|
30
31
|
setOverlays((current) => current.filter((entry) => entry.id !== id));
|
|
31
32
|
}, []);
|
|
32
33
|
|
|
34
|
+
const actions = React.useMemo(
|
|
35
|
+
() => ({
|
|
36
|
+
removeOverlay,
|
|
37
|
+
setOverlay,
|
|
38
|
+
}),
|
|
39
|
+
[removeOverlay, setOverlay],
|
|
40
|
+
);
|
|
41
|
+
|
|
33
42
|
const value = React.useMemo(
|
|
34
43
|
() => ({
|
|
35
44
|
overlays,
|
|
@@ -40,35 +49,37 @@ export function OverlayProvider({ children }: { children: React.ReactNode }) {
|
|
|
40
49
|
);
|
|
41
50
|
|
|
42
51
|
return (
|
|
43
|
-
<
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
52
|
+
<OverlayStackActionsContext.Provider value={actions}>
|
|
53
|
+
<OverlayStackContext.Provider value={value}>
|
|
54
|
+
{children}
|
|
55
|
+
<View
|
|
56
|
+
pointerEvents="box-none"
|
|
57
|
+
style={{
|
|
58
|
+
bottom: 0,
|
|
59
|
+
left: 0,
|
|
60
|
+
position: 'absolute',
|
|
61
|
+
right: 0,
|
|
62
|
+
top: 0,
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
{overlays.map((overlay) => (
|
|
66
|
+
<View
|
|
67
|
+
key={overlay.id}
|
|
68
|
+
pointerEvents="box-none"
|
|
69
|
+
style={{
|
|
70
|
+
bottom: 0,
|
|
71
|
+
left: 0,
|
|
72
|
+
position: 'absolute',
|
|
73
|
+
right: 0,
|
|
74
|
+
top: 0,
|
|
75
|
+
zIndex: overlay.zIndex,
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
{overlay.node}
|
|
79
|
+
</View>
|
|
80
|
+
))}
|
|
81
|
+
</View>
|
|
82
|
+
</OverlayStackContext.Provider>
|
|
83
|
+
</OverlayStackActionsContext.Provider>
|
|
73
84
|
);
|
|
74
85
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
import type { OverlayLayer } from '../resolvers/resolveOverlayZIndex';
|
|
4
|
-
import {
|
|
4
|
+
import { useOverlayStackActions } from './useOverlayStack';
|
|
5
5
|
|
|
6
6
|
let portalCounter = 0;
|
|
7
7
|
|
|
@@ -12,25 +12,36 @@ export interface PortalProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function Portal({ children, layer = 'modal', visible = true }: PortalProps) {
|
|
15
|
-
const
|
|
15
|
+
const overlayActions = useOverlayStackActions();
|
|
16
16
|
const idRef = React.useRef(`surface-portal-${portalCounter++}`);
|
|
17
17
|
|
|
18
18
|
React.useEffect(() => {
|
|
19
|
-
if (!
|
|
19
|
+
if (!overlayActions || !visible) {
|
|
20
20
|
return undefined;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
return () => {
|
|
24
|
+
overlayActions.removeOverlay(idRef.current);
|
|
25
|
+
};
|
|
26
|
+
}, [overlayActions, visible]);
|
|
27
|
+
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
if (!overlayActions || !visible) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (children === undefined || children === null) {
|
|
34
|
+
overlayActions.removeOverlay(idRef.current);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
overlayActions.setOverlay(idRef.current, {
|
|
24
39
|
layer,
|
|
25
40
|
node: children,
|
|
26
41
|
});
|
|
42
|
+
}, [children, layer, overlayActions, visible]);
|
|
27
43
|
|
|
28
|
-
|
|
29
|
-
overlayStack.removeOverlay(idRef.current);
|
|
30
|
-
};
|
|
31
|
-
}, [children, layer, overlayStack, visible]);
|
|
32
|
-
|
|
33
|
-
if (!overlayStack) {
|
|
44
|
+
if (!overlayActions) {
|
|
34
45
|
return visible ? <>{children}</> : null;
|
|
35
46
|
}
|
|
36
47
|
|
|
@@ -15,12 +15,15 @@ export interface OverlayDescriptor {
|
|
|
15
15
|
node: React.ReactNode;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export interface
|
|
19
|
-
overlays: OverlayEntry[];
|
|
18
|
+
export interface OverlayStackActions {
|
|
20
19
|
setOverlay: (id: string, overlay: OverlayDescriptor) => void;
|
|
21
20
|
removeOverlay: (id: string) => void;
|
|
22
21
|
}
|
|
23
22
|
|
|
23
|
+
export interface OverlayStackRuntime extends OverlayStackActions {
|
|
24
|
+
overlays: OverlayEntry[];
|
|
25
|
+
}
|
|
26
|
+
|
|
24
27
|
export function sortOverlayEntries(entries: OverlayEntry[]): OverlayEntry[] {
|
|
25
28
|
const perLayerCounts: Partial<Record<OverlayLayer, number>> = {};
|
|
26
29
|
const normalizedEntries = [...entries]
|
|
@@ -42,10 +45,16 @@ export function sortOverlayEntries(entries: OverlayEntry[]): OverlayEntry[] {
|
|
|
42
45
|
|
|
43
46
|
export const OverlayStackContext = React.createContext<OverlayStackRuntime | null>(null);
|
|
44
47
|
|
|
48
|
+
export const OverlayStackActionsContext = React.createContext<OverlayStackActions | null>(null);
|
|
49
|
+
|
|
45
50
|
export function useOverlayStack(): OverlayStackRuntime | null {
|
|
46
51
|
return React.useContext(OverlayStackContext);
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
export function useOverlayStackActions(): OverlayStackActions | null {
|
|
55
|
+
return React.useContext(OverlayStackActionsContext);
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
export function createOverlayEntry(
|
|
50
59
|
id: string,
|
|
51
60
|
order: number,
|