@lattice-ui/layer 0.3.2 → 0.4.1
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/out/dismissable/DismissableLayer.luau +25 -16
- package/out/dismissable/events.d.ts +2 -1
- package/out/dismissable/events.luau +17 -2
- package/out/dismissable/layerStack.d.ts +0 -1
- package/out/dismissable/layerStack.luau +7 -33
- package/out/dismissable/types.d.ts +1 -1
- package/out/internals/env.d.ts +1 -0
- package/out/internals/env.luau +2 -0
- package/package.json +2 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
-- Compiled with roblox-ts v3.0.0
|
|
2
2
|
local TS = _G[script]
|
|
3
|
-
local
|
|
3
|
+
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
|
+
local FocusLayerProvider = _core.FocusLayerProvider
|
|
5
|
+
local React = _core.React
|
|
4
6
|
local DEFAULT_LAYER_IGNORE_GUI_INSET = TS.import(script, script.Parent.Parent, "internals", "constants").DEFAULT_LAYER_IGNORE_GUI_INSET
|
|
5
7
|
local Portal = TS.import(script, script.Parent.Parent, "portal", "Portal").Portal
|
|
6
8
|
local usePortalContext = TS.import(script, script.Parent.Parent, "portal", "PortalProvider").usePortalContext
|
|
@@ -24,13 +26,13 @@ local function DismissableLayer(props)
|
|
|
24
26
|
local shouldBlockOutsidePointer = props.modal == true or props.disableOutsidePointerEvents == true
|
|
25
27
|
local layerIgnoresGuiInset = DEFAULT_LAYER_IGNORE_GUI_INSET
|
|
26
28
|
local portalContext = usePortalContext()
|
|
27
|
-
local
|
|
29
|
+
local contentWrapperRef = React.useRef()
|
|
28
30
|
local stackOrder, setStackOrder = React.useState(0)
|
|
29
31
|
local enabledRef = useLatest(enabled)
|
|
32
|
+
local insideRefsRef = useLatest(props.insideRefs or {})
|
|
30
33
|
local onDismissRef = useLatest(props.onDismiss)
|
|
31
34
|
local onPointerDownOutsideRef = useLatest(props.onPointerDownOutside)
|
|
32
35
|
local onInteractOutsideRef = useLatest(props.onInteractOutside)
|
|
33
|
-
local onEscapeKeyDownRef = useLatest(props.onEscapeKeyDown)
|
|
34
36
|
local callPointerDownOutside = React.useCallback(function(event)
|
|
35
37
|
local _result = onPointerDownOutsideRef.current
|
|
36
38
|
if _result ~= nil then
|
|
@@ -43,12 +45,6 @@ local function DismissableLayer(props)
|
|
|
43
45
|
_result(event)
|
|
44
46
|
end
|
|
45
47
|
end, {})
|
|
46
|
-
local callEscape = React.useCallback(function(event)
|
|
47
|
-
local _result = onEscapeKeyDownRef.current
|
|
48
|
-
if _result ~= nil then
|
|
49
|
-
_result(event)
|
|
50
|
-
end
|
|
51
|
-
end, {})
|
|
52
48
|
local callDismiss = React.useCallback(function()
|
|
53
49
|
local _result = onDismissRef.current
|
|
54
50
|
if _result ~= nil then
|
|
@@ -61,24 +57,35 @@ local function DismissableLayer(props)
|
|
|
61
57
|
return enabledRef.current
|
|
62
58
|
end,
|
|
63
59
|
isPointerOutside = function(inputObject)
|
|
64
|
-
local
|
|
65
|
-
if not
|
|
60
|
+
local contentWrapper = contentWrapperRef.current
|
|
61
|
+
if not contentWrapper then
|
|
66
62
|
return false
|
|
67
63
|
end
|
|
68
|
-
|
|
64
|
+
local _exp = insideRefsRef.current
|
|
65
|
+
-- ▼ ReadonlyArray.map ▼
|
|
66
|
+
local _newValue = table.create(#_exp)
|
|
67
|
+
local _callback = function(ref)
|
|
68
|
+
return ref.current
|
|
69
|
+
end
|
|
70
|
+
for _k, _v in _exp do
|
|
71
|
+
_newValue[_k] = _callback(_v, _k - 1, _exp)
|
|
72
|
+
end
|
|
73
|
+
-- ▲ ReadonlyArray.map ▲
|
|
74
|
+
local insideRoots = _newValue
|
|
75
|
+
return isOutsidePointerEvent(inputObject, portalContext.container, contentWrapper, {
|
|
76
|
+
insideRoots = insideRoots,
|
|
69
77
|
layerIgnoresGuiInset = layerIgnoresGuiInset,
|
|
70
78
|
})
|
|
71
79
|
end,
|
|
72
80
|
onPointerDownOutside = callPointerDownOutside,
|
|
73
81
|
onInteractOutside = callInteractOutside,
|
|
74
|
-
onEscapeKeyDown = callEscape,
|
|
75
82
|
onDismiss = callDismiss,
|
|
76
83
|
})
|
|
77
84
|
setStackOrder(registration.mountOrder)
|
|
78
85
|
return function()
|
|
79
86
|
unregisterLayer(registration.id)
|
|
80
87
|
end
|
|
81
|
-
end, { callDismiss,
|
|
88
|
+
end, { callDismiss, callInteractOutside, callPointerDownOutside, enabledRef, insideRefsRef, layerIgnoresGuiInset, portalContext.container })
|
|
82
89
|
return React.createElement(Portal, nil, React.createElement("screengui", {
|
|
83
90
|
key = `Layer_{stackOrder}`,
|
|
84
91
|
DisplayOrder = portalContext.displayOrderBase + stackOrder,
|
|
@@ -102,9 +109,11 @@ local function DismissableLayer(props)
|
|
|
102
109
|
BorderSizePixel = 0,
|
|
103
110
|
Position = UDim2.fromScale(0, 0),
|
|
104
111
|
Size = UDim2.fromScale(1, 1),
|
|
105
|
-
ref =
|
|
112
|
+
ref = contentWrapperRef,
|
|
106
113
|
ZIndex = 1,
|
|
107
|
-
},
|
|
114
|
+
}, React.createElement(FocusLayerProvider, {
|
|
115
|
+
layerOrder = stackOrder,
|
|
116
|
+
}, props.children))))
|
|
108
117
|
end
|
|
109
118
|
return {
|
|
110
119
|
DismissableLayer = DismissableLayer,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { LayerInteractEvent } from "./types";
|
|
2
2
|
type OutsidePointerOptions = {
|
|
3
3
|
layerIgnoresGuiInset: boolean;
|
|
4
|
+
insideRoots?: Array<GuiObject | undefined>;
|
|
4
5
|
};
|
|
5
6
|
export declare function isPointerInput(inputObject: InputObject): boolean;
|
|
6
7
|
export declare function toLayerInteractEvent(originalEvent: InputObject): LayerInteractEvent;
|
|
7
|
-
export declare function isOutsidePointerEvent(inputObject: InputObject, container: BasePlayerGui,
|
|
8
|
+
export declare function isOutsidePointerEvent(inputObject: InputObject, container: BasePlayerGui, contentWrapper: GuiObject, options: OutsidePointerOptions): boolean;
|
|
8
9
|
export {};
|
|
@@ -15,6 +15,20 @@ local function toLayerInteractEvent(originalEvent)
|
|
|
15
15
|
}
|
|
16
16
|
return event
|
|
17
17
|
end
|
|
18
|
+
local function isWithinInsideRoots(hitObject, insideRoots)
|
|
19
|
+
for _, insideRoot in insideRoots do
|
|
20
|
+
if not insideRoot then
|
|
21
|
+
continue
|
|
22
|
+
end
|
|
23
|
+
if hitObject == insideRoot or hitObject:IsDescendantOf(insideRoot) then
|
|
24
|
+
return true
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
return false
|
|
28
|
+
end
|
|
29
|
+
local function isWithinContentBoundary(hitObject, contentWrapper)
|
|
30
|
+
return hitObject:IsDescendantOf(contentWrapper)
|
|
31
|
+
end
|
|
18
32
|
local function addUniqueSample(samples, sampleKeys, x, y)
|
|
19
33
|
local roundedX = math.round(x)
|
|
20
34
|
local roundedY = math.round(y)
|
|
@@ -42,14 +56,15 @@ local function getPointerSamples(pointerPosition, options)
|
|
|
42
56
|
end
|
|
43
57
|
return samples
|
|
44
58
|
end
|
|
45
|
-
local function isOutsidePointerEvent(inputObject, container,
|
|
59
|
+
local function isOutsidePointerEvent(inputObject, container, contentWrapper, options)
|
|
46
60
|
local rawPointerPosition = inputObject.Position
|
|
47
61
|
local pointerPosition = Vector2.new(rawPointerPosition.X, rawPointerPosition.Y)
|
|
48
62
|
local pointerSamples = getPointerSamples(pointerPosition, options)
|
|
63
|
+
local insideRoots = options.insideRoots or {}
|
|
49
64
|
for _, sample in pointerSamples do
|
|
50
65
|
local hitGuiObjects = container:GetGuiObjectsAtPosition(sample.X, sample.Y)
|
|
51
66
|
for _1, hitObject in hitGuiObjects do
|
|
52
|
-
if hitObject
|
|
67
|
+
if isWithinContentBoundary(hitObject, contentWrapper) or isWithinInsideRoots(hitObject, insideRoots) then
|
|
53
68
|
return false
|
|
54
69
|
end
|
|
55
70
|
end
|
|
@@ -6,7 +6,6 @@ type LayerEntry = {
|
|
|
6
6
|
isPointerOutside: (inputObject: InputObject) => boolean;
|
|
7
7
|
onPointerDownOutside?: (event: LayerInteractEvent) => void;
|
|
8
8
|
onInteractOutside?: (event: LayerInteractEvent) => void;
|
|
9
|
-
onEscapeKeyDown?: (event: LayerInteractEvent) => void;
|
|
10
9
|
onDismiss?: () => void;
|
|
11
10
|
};
|
|
12
11
|
type RegisterLayerParams = Omit<LayerEntry, "id" | "mountOrder">;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
-- Compiled with roblox-ts v3.0.0
|
|
2
2
|
local TS = _G[script]
|
|
3
|
-
local
|
|
4
|
-
local GuiService = _env.GuiService
|
|
5
|
-
local UserInputService = _env.UserInputService
|
|
3
|
+
local UserInputService = TS.import(script, script.Parent.Parent, "internals", "env").UserInputService
|
|
6
4
|
local _events = TS.import(script, script.Parent, "events")
|
|
7
5
|
local isPointerInput = _events.isPointerInput
|
|
8
6
|
local toLayerInteractEvent = _events.toLayerInteractEvent
|
|
@@ -27,38 +25,15 @@ local function handleDismissEvent(entry, event)
|
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
end
|
|
30
|
-
local function shouldIgnoreEscapeDismiss()
|
|
31
|
-
local focusedTextBox = UserInputService:GetFocusedTextBox()
|
|
32
|
-
if focusedTextBox then
|
|
33
|
-
return true
|
|
34
|
-
end
|
|
35
|
-
local selectedObject = GuiService.SelectedObject
|
|
36
|
-
if selectedObject and selectedObject:IsA("TextBox") then
|
|
37
|
-
return true
|
|
38
|
-
end
|
|
39
|
-
return false
|
|
40
|
-
end
|
|
41
28
|
local function handleInputBegan(inputObject, gameProcessedEvent)
|
|
42
29
|
if gameProcessedEvent then
|
|
43
30
|
return nil
|
|
44
31
|
end
|
|
45
|
-
|
|
46
|
-
if not topLayer then
|
|
47
|
-
return nil
|
|
48
|
-
end
|
|
49
|
-
if inputObject.KeyCode == Enum.KeyCode.Escape then
|
|
50
|
-
if shouldIgnoreEscapeDismiss() then
|
|
51
|
-
return nil
|
|
52
|
-
end
|
|
53
|
-
local escapeEvent = toLayerInteractEvent(inputObject)
|
|
54
|
-
local _result = topLayer.onEscapeKeyDown
|
|
55
|
-
if _result ~= nil then
|
|
56
|
-
_result(escapeEvent)
|
|
57
|
-
end
|
|
58
|
-
handleDismissEvent(topLayer, escapeEvent)
|
|
32
|
+
if not isPointerInput(inputObject) then
|
|
59
33
|
return nil
|
|
60
34
|
end
|
|
61
|
-
|
|
35
|
+
local topLayer = getTopMostEnabledLayer()
|
|
36
|
+
if not topLayer then
|
|
62
37
|
return nil
|
|
63
38
|
end
|
|
64
39
|
if not topLayer.isPointerOutside(inputObject) then
|
|
@@ -84,11 +59,10 @@ local function startInputListener()
|
|
|
84
59
|
end)
|
|
85
60
|
end
|
|
86
61
|
local function stopInputListener()
|
|
87
|
-
if
|
|
88
|
-
|
|
62
|
+
if inputConnection then
|
|
63
|
+
inputConnection:Disconnect()
|
|
64
|
+
inputConnection = nil
|
|
89
65
|
end
|
|
90
|
-
inputConnection:Disconnect()
|
|
91
|
-
inputConnection = nil
|
|
92
66
|
end
|
|
93
67
|
local function syncInputListener()
|
|
94
68
|
if #layerEntries > 0 then
|
|
@@ -7,10 +7,10 @@ export type LayerInteractEvent = {
|
|
|
7
7
|
export type DismissableLayerProps = {
|
|
8
8
|
children?: React.ReactNode;
|
|
9
9
|
enabled?: boolean;
|
|
10
|
+
insideRefs?: Array<React.MutableRefObject<GuiObject | undefined> | React.MutableRefObject<TextBox | undefined>>;
|
|
10
11
|
modal?: boolean;
|
|
11
12
|
disableOutsidePointerEvents?: boolean;
|
|
12
13
|
onPointerDownOutside?: (event: LayerInteractEvent) => void;
|
|
13
14
|
onInteractOutside?: (event: LayerInteractEvent) => void;
|
|
14
|
-
onEscapeKeyDown?: (event: LayerInteractEvent) => void;
|
|
15
15
|
onDismiss?: () => void;
|
|
16
16
|
};
|
package/out/internals/env.d.ts
CHANGED
package/out/internals/env.luau
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
-- Compiled with roblox-ts v3.0.0
|
|
2
2
|
local UserInputService = game:GetService("UserInputService")
|
|
3
3
|
local GuiService = game:GetService("GuiService")
|
|
4
|
+
local ContextActionService = game:GetService("ContextActionService")
|
|
4
5
|
local function getGuiInsetTopLeft()
|
|
5
6
|
local topLeftInset = GuiService:GetGuiInset()
|
|
6
7
|
return topLeftInset
|
|
@@ -9,4 +10,5 @@ return {
|
|
|
9
10
|
getGuiInsetTopLeft = getGuiInsetTopLeft,
|
|
10
11
|
UserInputService = UserInputService,
|
|
11
12
|
GuiService = GuiService,
|
|
13
|
+
ContextActionService = ContextActionService,
|
|
12
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lattice-ui/layer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "out/init.luau",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"README.md"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@lattice-ui/core": "0.
|
|
12
|
+
"@lattice-ui/core": "0.4.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@rbxts/react": "17.3.7-ts.1",
|