@lattice-ui/radio-group 0.3.2 → 0.4.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.
|
@@ -3,25 +3,77 @@ local TS = _G[script]
|
|
|
3
3
|
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
4
|
local React = _core.React
|
|
5
5
|
local Slot = _core.Slot
|
|
6
|
-
local
|
|
6
|
+
local useFocusNode = _core.useFocusNode
|
|
7
7
|
local _context = TS.import(script, script.Parent, "context")
|
|
8
8
|
local RadioGroupItemContextProvider = _context.RadioGroupItemContextProvider
|
|
9
9
|
local useRadioGroupContext = _context.useRadioGroupContext
|
|
10
|
+
local nextItemId = 0
|
|
11
|
+
local nextItemOrder = 0
|
|
10
12
|
local function RadioGroupItem(props)
|
|
11
13
|
local radioGroupContext = useRadioGroupContext()
|
|
12
14
|
local disabled = radioGroupContext.disabled or props.disabled == true
|
|
13
15
|
local checked = radioGroupContext.value == props.value
|
|
16
|
+
local itemRef = React.useRef()
|
|
17
|
+
local disabledRef = React.useRef(disabled)
|
|
18
|
+
React.useEffect(function()
|
|
19
|
+
disabledRef.current = disabled
|
|
20
|
+
end, { disabled })
|
|
21
|
+
local itemIdRef = React.useRef(0)
|
|
22
|
+
if itemIdRef.current == 0 then
|
|
23
|
+
nextItemId += 1
|
|
24
|
+
itemIdRef.current = nextItemId
|
|
25
|
+
end
|
|
26
|
+
local itemOrderRef = React.useRef(0)
|
|
27
|
+
if itemOrderRef.current == 0 then
|
|
28
|
+
nextItemOrder += 1
|
|
29
|
+
itemOrderRef.current = nextItemOrder
|
|
30
|
+
end
|
|
31
|
+
React.useEffect(function()
|
|
32
|
+
return radioGroupContext.registerItem({
|
|
33
|
+
id = itemIdRef.current,
|
|
34
|
+
value = props.value,
|
|
35
|
+
order = itemOrderRef.current,
|
|
36
|
+
ref = itemRef,
|
|
37
|
+
getDisabled = function()
|
|
38
|
+
return disabledRef.current
|
|
39
|
+
end,
|
|
40
|
+
})
|
|
41
|
+
end, { props.value, radioGroupContext })
|
|
42
|
+
useFocusNode({
|
|
43
|
+
ref = itemRef,
|
|
44
|
+
getDisabled = function()
|
|
45
|
+
return disabledRef.current
|
|
46
|
+
end,
|
|
47
|
+
})
|
|
48
|
+
local setItemRef = React.useCallback(function(instance)
|
|
49
|
+
if not instance or not instance:IsA("GuiObject") then
|
|
50
|
+
itemRef.current = nil
|
|
51
|
+
return nil
|
|
52
|
+
end
|
|
53
|
+
itemRef.current = instance
|
|
54
|
+
end, {})
|
|
14
55
|
local handleSelect = React.useCallback(function()
|
|
15
56
|
if disabled then
|
|
16
57
|
return nil
|
|
17
58
|
end
|
|
18
59
|
radioGroupContext.setValue(props.value)
|
|
19
60
|
end, { disabled, props.value, radioGroupContext })
|
|
61
|
+
local handleSelectionGained = React.useCallback(function()
|
|
62
|
+
if disabled then
|
|
63
|
+
return nil
|
|
64
|
+
end
|
|
65
|
+
radioGroupContext.setValue(props.value)
|
|
66
|
+
end, { disabled, props.value, radioGroupContext })
|
|
20
67
|
local handleInputBegan = React.useCallback(function(_rbx, inputObject)
|
|
21
68
|
if disabled then
|
|
22
69
|
return nil
|
|
23
70
|
end
|
|
24
71
|
local keyCode = inputObject.KeyCode
|
|
72
|
+
local direction = if radioGroupContext.orientation == "horizontal" then if keyCode == Enum.KeyCode.Left then -1 elseif keyCode == Enum.KeyCode.Right then 1 else nil elseif keyCode == Enum.KeyCode.Up then -1 elseif keyCode == Enum.KeyCode.Down then 1 else nil
|
|
73
|
+
if direction ~= nil then
|
|
74
|
+
radioGroupContext.moveSelection(props.value, direction)
|
|
75
|
+
return nil
|
|
76
|
+
end
|
|
25
77
|
if keyCode ~= Enum.KeyCode.Return and keyCode ~= Enum.KeyCode.Space then
|
|
26
78
|
return nil
|
|
27
79
|
end
|
|
@@ -30,10 +82,10 @@ local function RadioGroupItem(props)
|
|
|
30
82
|
local eventHandlers = React.useMemo(function()
|
|
31
83
|
return {
|
|
32
84
|
Activated = handleSelect,
|
|
33
|
-
SelectionGained = handleSelect,
|
|
34
85
|
InputBegan = handleInputBegan,
|
|
86
|
+
SelectionGained = handleSelectionGained,
|
|
35
87
|
}
|
|
36
|
-
end, { handleInputBegan, handleSelect })
|
|
88
|
+
end, { handleInputBegan, handleSelect, handleSelectionGained })
|
|
37
89
|
local itemContextValue = React.useMemo(function()
|
|
38
90
|
return {
|
|
39
91
|
checked = checked,
|
|
@@ -47,18 +99,13 @@ local function RadioGroupItem(props)
|
|
|
47
99
|
if not child then
|
|
48
100
|
error("[RadioGroupItem] `asChild` requires a child element.")
|
|
49
101
|
end
|
|
50
|
-
return React.createElement(
|
|
51
|
-
asChild = true,
|
|
52
|
-
disabled = disabled,
|
|
53
|
-
}, React.createElement(Slot, {
|
|
102
|
+
return React.createElement(Slot, {
|
|
54
103
|
Active = not disabled,
|
|
55
104
|
Event = eventHandlers,
|
|
56
105
|
Selectable = not disabled,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
disabled = disabled,
|
|
61
|
-
}, React.createElement("textbutton", {
|
|
106
|
+
ref = setItemRef,
|
|
107
|
+
}, child)
|
|
108
|
+
end)()) else (React.createElement("textbutton", {
|
|
62
109
|
Active = not disabled,
|
|
63
110
|
AutoButtonColor = false,
|
|
64
111
|
BackgroundColor3 = if checked then Color3.fromRGB(88, 142, 255) else Color3.fromRGB(47, 53, 68),
|
|
@@ -69,7 +116,8 @@ local function RadioGroupItem(props)
|
|
|
69
116
|
Text = props.value,
|
|
70
117
|
TextColor3 = if disabled then Color3.fromRGB(139, 146, 160) else Color3.fromRGB(236, 241, 249),
|
|
71
118
|
TextSize = 15,
|
|
72
|
-
|
|
119
|
+
ref = setItemRef,
|
|
120
|
+
}, props.children)))
|
|
73
121
|
end
|
|
74
122
|
return {
|
|
75
123
|
RadioGroupItem = RadioGroupItem,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
-- Compiled with roblox-ts v3.0.0
|
|
2
2
|
local TS = _G[script]
|
|
3
3
|
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
|
+
local findOrderedSelectionEntry = _core.findOrderedSelectionEntry
|
|
5
|
+
local focusOrderedSelectionEntry = _core.focusOrderedSelectionEntry
|
|
6
|
+
local getRelativeOrderedSelectionEntry = _core.getRelativeOrderedSelectionEntry
|
|
4
7
|
local React = _core.React
|
|
5
8
|
local useControllableState = _core.useControllableState
|
|
6
|
-
local RovingFocusGroup = TS.import(script, TS.getModule(script, "@lattice-ui", "focus").out).RovingFocusGroup
|
|
7
9
|
local RadioGroupContextProvider = TS.import(script, script.Parent, "context").RadioGroupContextProvider
|
|
8
10
|
local function RadioGroupRoot(props)
|
|
11
|
+
local orientation = props.orientation or "vertical"
|
|
9
12
|
local _binding = useControllableState({
|
|
10
13
|
value = props.value,
|
|
11
14
|
defaultValue = props.defaultValue,
|
|
@@ -22,34 +25,74 @@ local function RadioGroupRoot(props)
|
|
|
22
25
|
local setValueState = _binding[2]
|
|
23
26
|
local disabled = props.disabled == true
|
|
24
27
|
local required = props.required == true
|
|
25
|
-
local
|
|
26
|
-
|
|
27
|
-
_condition = true
|
|
28
|
-
end
|
|
29
|
-
local loop = _condition
|
|
30
|
-
local orientation = props.orientation or "vertical"
|
|
28
|
+
local itemEntriesRef = React.useRef({})
|
|
29
|
+
local _, setRegistryRevision = React.useState(0)
|
|
31
30
|
local setValue = React.useCallback(function(nextValue)
|
|
32
31
|
if disabled then
|
|
33
32
|
return nil
|
|
34
33
|
end
|
|
35
34
|
setValueState(nextValue)
|
|
36
35
|
end, { disabled, setValueState })
|
|
36
|
+
local registerItem = React.useCallback(function(item)
|
|
37
|
+
local _current = itemEntriesRef.current
|
|
38
|
+
local _item = item
|
|
39
|
+
table.insert(_current, _item)
|
|
40
|
+
setRegistryRevision(function(revision)
|
|
41
|
+
return revision + 1
|
|
42
|
+
end)
|
|
43
|
+
return function()
|
|
44
|
+
local _exp = itemEntriesRef.current
|
|
45
|
+
-- ▼ ReadonlyArray.findIndex ▼
|
|
46
|
+
local _callback = function(entry)
|
|
47
|
+
return entry.id == item.id
|
|
48
|
+
end
|
|
49
|
+
local _result = -1
|
|
50
|
+
for _i, _v in _exp do
|
|
51
|
+
if _callback(_v, _i - 1, _exp) == true then
|
|
52
|
+
_result = _i - 1
|
|
53
|
+
break
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
-- ▲ ReadonlyArray.findIndex ▲
|
|
57
|
+
local index = _result
|
|
58
|
+
if index >= 0 then
|
|
59
|
+
table.remove(itemEntriesRef.current, index + 1)
|
|
60
|
+
setRegistryRevision(function(revision)
|
|
61
|
+
return revision + 1
|
|
62
|
+
end)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end, {})
|
|
66
|
+
local moveSelection = React.useCallback(function(fromValue, direction)
|
|
67
|
+
local currentItem = findOrderedSelectionEntry(itemEntriesRef.current, function(item)
|
|
68
|
+
return item.value == fromValue
|
|
69
|
+
end) or nil
|
|
70
|
+
local _exp = itemEntriesRef.current
|
|
71
|
+
local _result = currentItem
|
|
72
|
+
if _result ~= nil then
|
|
73
|
+
_result = _result.id
|
|
74
|
+
end
|
|
75
|
+
local nextItem = getRelativeOrderedSelectionEntry(_exp, _result, direction)
|
|
76
|
+
if not nextItem then
|
|
77
|
+
return nil
|
|
78
|
+
end
|
|
79
|
+
focusOrderedSelectionEntry(nextItem)
|
|
80
|
+
setValue(nextItem.value)
|
|
81
|
+
end, { setValue })
|
|
37
82
|
local contextValue = React.useMemo(function()
|
|
38
83
|
return {
|
|
39
84
|
value = value,
|
|
40
85
|
setValue = setValue,
|
|
41
86
|
disabled = disabled,
|
|
42
87
|
required = required,
|
|
88
|
+
orientation = orientation,
|
|
89
|
+
registerItem = registerItem,
|
|
90
|
+
moveSelection = moveSelection,
|
|
43
91
|
}
|
|
44
|
-
end, { disabled, required, setValue, value })
|
|
92
|
+
end, { disabled, moveSelection, orientation, registerItem, required, setValue, value })
|
|
45
93
|
return React.createElement(RadioGroupContextProvider, {
|
|
46
94
|
value = contextValue,
|
|
47
|
-
},
|
|
48
|
-
active = not disabled,
|
|
49
|
-
autoFocus = "none",
|
|
50
|
-
loop = loop,
|
|
51
|
-
orientation = orientation,
|
|
52
|
-
}, props.children))
|
|
95
|
+
}, props.children)
|
|
53
96
|
end
|
|
54
97
|
return {
|
|
55
98
|
RadioGroupRoot = RadioGroupRoot,
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import type React from "@rbxts/react";
|
|
2
|
-
export type RadioGroupOrientation = "horizontal" | "vertical" | "both";
|
|
3
2
|
export type RadioGroupSetValue = (value: string) => void;
|
|
3
|
+
export type RadioGroupOrientation = "horizontal" | "vertical";
|
|
4
|
+
export type RadioGroupItemRegistration = {
|
|
5
|
+
id: number;
|
|
6
|
+
value: string;
|
|
7
|
+
order: number;
|
|
8
|
+
ref: React.MutableRefObject<GuiObject | undefined>;
|
|
9
|
+
getDisabled: () => boolean;
|
|
10
|
+
};
|
|
4
11
|
export type RadioGroupContextValue = {
|
|
5
12
|
value?: string;
|
|
6
13
|
setValue: RadioGroupSetValue;
|
|
7
14
|
disabled: boolean;
|
|
8
15
|
required: boolean;
|
|
16
|
+
orientation: RadioGroupOrientation;
|
|
17
|
+
registerItem: (item: RadioGroupItemRegistration) => () => void;
|
|
18
|
+
moveSelection: (fromValue: string, direction: -1 | 1) => void;
|
|
9
19
|
};
|
|
10
20
|
export type RadioGroupItemContextValue = {
|
|
11
21
|
checked: boolean;
|
|
@@ -17,7 +27,6 @@ export type RadioGroupProps = {
|
|
|
17
27
|
onValueChange?: (value: string) => void;
|
|
18
28
|
disabled?: boolean;
|
|
19
29
|
required?: boolean;
|
|
20
|
-
loop?: boolean;
|
|
21
30
|
orientation?: RadioGroupOrientation;
|
|
22
31
|
children?: React.ReactNode;
|
|
23
32
|
};
|
package/out/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export declare const RadioGroup: {
|
|
|
6
6
|
readonly Item: typeof RadioGroupItem;
|
|
7
7
|
readonly Indicator: typeof RadioGroupIndicator;
|
|
8
8
|
};
|
|
9
|
+
export type { RadioGroupContextValue, RadioGroupIndicatorProps, RadioGroupItemContextValue, RadioGroupItemProps, RadioGroupItemRegistration, RadioGroupOrientation, RadioGroupProps, RadioGroupSetValue, } from "./RadioGroup/types";
|
|
9
10
|
export { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot };
|
|
10
|
-
export type { RadioGroupContextValue, RadioGroupIndicatorProps, RadioGroupItemContextValue, RadioGroupItemProps, RadioGroupProps, RadioGroupSetValue, } from "./RadioGroup/types";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lattice-ui/radio-group",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "out/init.luau",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"README.md"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@lattice-ui/core": "0.
|
|
13
|
-
"@lattice-ui/focus": "0.3.2"
|
|
12
|
+
"@lattice-ui/core": "0.4.0"
|
|
14
13
|
},
|
|
15
14
|
"devDependencies": {
|
|
16
15
|
"@rbxts/react": "17.3.7-ts.1",
|