@lattice-ui/combobox 0.3.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/README.md +23 -0
- package/out/Combobox/ComboboxContent.d.ts +3 -0
- package/out/Combobox/ComboboxContent.luau +110 -0
- package/out/Combobox/ComboboxGroup.d.ts +3 -0
- package/out/Combobox/ComboboxGroup.luau +22 -0
- package/out/Combobox/ComboboxInput.d.ts +3 -0
- package/out/Combobox/ComboboxInput.luau +88 -0
- package/out/Combobox/ComboboxItem.d.ts +3 -0
- package/out/Combobox/ComboboxItem.luau +131 -0
- package/out/Combobox/ComboboxLabel.d.ts +3 -0
- package/out/Combobox/ComboboxLabel.luau +26 -0
- package/out/Combobox/ComboboxPortal.d.ts +3 -0
- package/out/Combobox/ComboboxPortal.luau +33 -0
- package/out/Combobox/ComboboxRoot.d.ts +4 -0
- package/out/Combobox/ComboboxRoot.luau +256 -0
- package/out/Combobox/ComboboxSeparator.d.ts +3 -0
- package/out/Combobox/ComboboxSeparator.luau +22 -0
- package/out/Combobox/ComboboxTrigger.d.ts +3 -0
- package/out/Combobox/ComboboxTrigger.luau +72 -0
- package/out/Combobox/ComboboxValue.d.ts +3 -0
- package/out/Combobox/ComboboxValue.luau +47 -0
- package/out/Combobox/context.d.ts +3 -0
- package/out/Combobox/context.luau +10 -0
- package/out/Combobox/logic.d.ts +10 -0
- package/out/Combobox/logic.luau +103 -0
- package/out/Combobox/types.d.ts +105 -0
- package/out/Combobox/types.luau +2 -0
- package/out/index.d.ts +24 -0
- package/out/init.luau +32 -0
- package/package.json +26 -0
- package/src/Combobox/ComboboxContent.tsx +142 -0
- package/src/Combobox/ComboboxGroup.tsx +19 -0
- package/src/Combobox/ComboboxInput.tsx +98 -0
- package/src/Combobox/ComboboxItem.tsx +134 -0
- package/src/Combobox/ComboboxLabel.tsx +27 -0
- package/src/Combobox/ComboboxPortal.tsx +28 -0
- package/src/Combobox/ComboboxRoot.tsx +202 -0
- package/src/Combobox/ComboboxSeparator.tsx +19 -0
- package/src/Combobox/ComboboxTrigger.tsx +89 -0
- package/src/Combobox/ComboboxValue.tsx +42 -0
- package/src/Combobox/context.ts +6 -0
- package/src/Combobox/logic.ts +56 -0
- package/src/Combobox/types.ts +119 -0
- package/src/index.ts +48 -0
- package/tsconfig.json +16 -0
- package/tsconfig.typecheck.json +35 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
|
+
local React = _core.React
|
|
5
|
+
local useControllableState = _core.useControllableState
|
|
6
|
+
local ComboboxContextProvider = TS.import(script, script.Parent, "context").ComboboxContextProvider
|
|
7
|
+
local _logic = TS.import(script, script.Parent, "logic")
|
|
8
|
+
local defaultComboboxFilter = _logic.defaultComboboxFilter
|
|
9
|
+
local resolveComboboxInputValue = _logic.resolveComboboxInputValue
|
|
10
|
+
local resolveForcedComboboxValue = _logic.resolveForcedComboboxValue
|
|
11
|
+
local function getOrderedItems(items)
|
|
12
|
+
local _array = {}
|
|
13
|
+
local _length = #_array
|
|
14
|
+
table.move(items, 1, #items, _length + 1, _array)
|
|
15
|
+
local ordered = _array
|
|
16
|
+
table.sort(ordered, function(left, right)
|
|
17
|
+
return left.order < right.order
|
|
18
|
+
end)
|
|
19
|
+
return ordered
|
|
20
|
+
end
|
|
21
|
+
local function toOptions(items)
|
|
22
|
+
-- ▼ ReadonlyArray.map ▼
|
|
23
|
+
local _newValue = table.create(#items)
|
|
24
|
+
local _callback = function(item)
|
|
25
|
+
return {
|
|
26
|
+
value = item.value,
|
|
27
|
+
disabled = item.getDisabled(),
|
|
28
|
+
textValue = item.getTextValue(),
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
for _k, _v in items do
|
|
32
|
+
_newValue[_k] = _callback(_v, _k - 1, items)
|
|
33
|
+
end
|
|
34
|
+
-- ▲ ReadonlyArray.map ▲
|
|
35
|
+
return _newValue
|
|
36
|
+
end
|
|
37
|
+
local function ComboboxRoot(props)
|
|
38
|
+
local _object = {
|
|
39
|
+
value = props.open,
|
|
40
|
+
}
|
|
41
|
+
local _left = "defaultValue"
|
|
42
|
+
local _condition = props.defaultOpen
|
|
43
|
+
if _condition == nil then
|
|
44
|
+
_condition = false
|
|
45
|
+
end
|
|
46
|
+
_object[_left] = _condition
|
|
47
|
+
_object.onChange = props.onOpenChange
|
|
48
|
+
local _binding = useControllableState(_object)
|
|
49
|
+
local open = _binding[1]
|
|
50
|
+
local setOpenState = _binding[2]
|
|
51
|
+
local _binding_1 = useControllableState({
|
|
52
|
+
value = props.value,
|
|
53
|
+
defaultValue = props.defaultValue,
|
|
54
|
+
onChange = function(nextValue)
|
|
55
|
+
if nextValue ~= nil then
|
|
56
|
+
local _result = props.onValueChange
|
|
57
|
+
if _result ~= nil then
|
|
58
|
+
_result(nextValue)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end,
|
|
62
|
+
})
|
|
63
|
+
local value = _binding_1[1]
|
|
64
|
+
local setValueState = _binding_1[2]
|
|
65
|
+
local _object_1 = {
|
|
66
|
+
value = props.inputValue,
|
|
67
|
+
}
|
|
68
|
+
local _left_1 = "defaultValue"
|
|
69
|
+
local _condition_1 = props.defaultInputValue
|
|
70
|
+
if _condition_1 == nil then
|
|
71
|
+
_condition_1 = ""
|
|
72
|
+
end
|
|
73
|
+
_object_1[_left_1] = _condition_1
|
|
74
|
+
_object_1.onChange = props.onInputValueChange
|
|
75
|
+
local _binding_2 = useControllableState(_object_1)
|
|
76
|
+
local inputValue = _binding_2[1]
|
|
77
|
+
local setInputValueState = _binding_2[2]
|
|
78
|
+
local disabled = props.disabled == true
|
|
79
|
+
local readOnly = props.readOnly == true
|
|
80
|
+
local required = props.required == true
|
|
81
|
+
local _condition_2 = props.loop
|
|
82
|
+
if _condition_2 == nil then
|
|
83
|
+
_condition_2 = true
|
|
84
|
+
end
|
|
85
|
+
local loop = _condition_2
|
|
86
|
+
local filterFn = props.filterFn or defaultComboboxFilter
|
|
87
|
+
local triggerRef = React.useRef()
|
|
88
|
+
local inputRef = React.useRef()
|
|
89
|
+
local contentRef = React.useRef()
|
|
90
|
+
local itemEntriesRef = React.useRef({})
|
|
91
|
+
local registryRevision, setRegistryRevision = React.useState(0)
|
|
92
|
+
local registerItem = React.useCallback(function(item)
|
|
93
|
+
local _current = itemEntriesRef.current
|
|
94
|
+
local _item = item
|
|
95
|
+
table.insert(_current, _item)
|
|
96
|
+
setRegistryRevision(function(revision)
|
|
97
|
+
return revision + 1
|
|
98
|
+
end)
|
|
99
|
+
return function()
|
|
100
|
+
local _exp = itemEntriesRef.current
|
|
101
|
+
-- ▼ ReadonlyArray.findIndex ▼
|
|
102
|
+
local _callback = function(entry)
|
|
103
|
+
return entry.id == item.id
|
|
104
|
+
end
|
|
105
|
+
local _result = -1
|
|
106
|
+
for _i, _v in _exp do
|
|
107
|
+
if _callback(_v, _i - 1, _exp) == true then
|
|
108
|
+
_result = _i - 1
|
|
109
|
+
break
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
-- ▲ ReadonlyArray.findIndex ▲
|
|
113
|
+
local index = _result
|
|
114
|
+
if index >= 0 then
|
|
115
|
+
table.remove(itemEntriesRef.current, index + 1)
|
|
116
|
+
setRegistryRevision(function(revision)
|
|
117
|
+
return revision + 1
|
|
118
|
+
end)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end, {})
|
|
122
|
+
local resolveOrderedItems = React.useCallback(function()
|
|
123
|
+
return getOrderedItems(itemEntriesRef.current)
|
|
124
|
+
end, { registryRevision })
|
|
125
|
+
local getItemText = React.useCallback(function(candidateValue)
|
|
126
|
+
local _exp = resolveOrderedItems()
|
|
127
|
+
-- ▼ ReadonlyArray.find ▼
|
|
128
|
+
local _callback = function(item)
|
|
129
|
+
return item.value == candidateValue
|
|
130
|
+
end
|
|
131
|
+
local _result
|
|
132
|
+
for _i, _v in _exp do
|
|
133
|
+
if _callback(_v, _i - 1, _exp) == true then
|
|
134
|
+
_result = _v
|
|
135
|
+
break
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
-- ▲ ReadonlyArray.find ▲
|
|
139
|
+
local selected = _result
|
|
140
|
+
local _result_1 = selected
|
|
141
|
+
if _result_1 ~= nil then
|
|
142
|
+
_result_1 = _result_1.getTextValue()
|
|
143
|
+
end
|
|
144
|
+
return _result_1
|
|
145
|
+
end, { resolveOrderedItems })
|
|
146
|
+
local syncInputFromValue = React.useCallback(function()
|
|
147
|
+
local nextInputValue = resolveComboboxInputValue(value, toOptions(resolveOrderedItems()), "")
|
|
148
|
+
setInputValueState(nextInputValue)
|
|
149
|
+
end, { resolveOrderedItems, setInputValueState, value })
|
|
150
|
+
local setOpen = React.useCallback(function(nextOpen)
|
|
151
|
+
if disabled and nextOpen then
|
|
152
|
+
return nil
|
|
153
|
+
end
|
|
154
|
+
setOpenState(nextOpen)
|
|
155
|
+
if not nextOpen then
|
|
156
|
+
syncInputFromValue()
|
|
157
|
+
end
|
|
158
|
+
end, { disabled, setOpenState, syncInputFromValue })
|
|
159
|
+
local setValue = React.useCallback(function(nextValue)
|
|
160
|
+
if disabled then
|
|
161
|
+
return nil
|
|
162
|
+
end
|
|
163
|
+
local _exp = resolveOrderedItems()
|
|
164
|
+
-- ▼ ReadonlyArray.find ▼
|
|
165
|
+
local _callback = function(item)
|
|
166
|
+
return item.value == nextValue
|
|
167
|
+
end
|
|
168
|
+
local _result
|
|
169
|
+
for _i, _v in _exp do
|
|
170
|
+
if _callback(_v, _i - 1, _exp) == true then
|
|
171
|
+
_result = _v
|
|
172
|
+
break
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
-- ▲ ReadonlyArray.find ▲
|
|
176
|
+
local selected = _result
|
|
177
|
+
if selected and selected.getDisabled() then
|
|
178
|
+
return nil
|
|
179
|
+
end
|
|
180
|
+
setValueState(nextValue)
|
|
181
|
+
local _condition_3 = getItemText(nextValue)
|
|
182
|
+
if _condition_3 == nil then
|
|
183
|
+
_condition_3 = nextValue
|
|
184
|
+
end
|
|
185
|
+
local nextInputValue = _condition_3
|
|
186
|
+
setInputValueState(nextInputValue)
|
|
187
|
+
end, { disabled, getItemText, resolveOrderedItems, setInputValueState, setValueState })
|
|
188
|
+
local setInputValue = React.useCallback(function(nextInputValue)
|
|
189
|
+
if disabled or readOnly then
|
|
190
|
+
return nil
|
|
191
|
+
end
|
|
192
|
+
setInputValueState(nextInputValue)
|
|
193
|
+
setOpenState(true)
|
|
194
|
+
end, { disabled, readOnly, setInputValueState, setOpenState })
|
|
195
|
+
local getFilteredItems = React.useCallback(function()
|
|
196
|
+
local query = inputValue
|
|
197
|
+
local _exp = resolveOrderedItems()
|
|
198
|
+
-- ▼ ReadonlyArray.filter ▼
|
|
199
|
+
local _newValue = {}
|
|
200
|
+
local _callback = function(item)
|
|
201
|
+
return filterFn(item.getTextValue(), query)
|
|
202
|
+
end
|
|
203
|
+
local _length = 0
|
|
204
|
+
for _k, _v in _exp do
|
|
205
|
+
if _callback(_v, _k - 1, _exp) == true then
|
|
206
|
+
_length += 1
|
|
207
|
+
_newValue[_length] = _v
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
-- ▲ ReadonlyArray.filter ▲
|
|
211
|
+
return _newValue
|
|
212
|
+
end, { filterFn, inputValue, resolveOrderedItems })
|
|
213
|
+
React.useEffect(function()
|
|
214
|
+
local orderedItems = resolveOrderedItems()
|
|
215
|
+
local nextValue = resolveForcedComboboxValue(value, toOptions(orderedItems))
|
|
216
|
+
if nextValue ~= value then
|
|
217
|
+
setValueState(nextValue)
|
|
218
|
+
end
|
|
219
|
+
end, { registryRevision, resolveOrderedItems, setValueState, value })
|
|
220
|
+
React.useEffect(function()
|
|
221
|
+
if open then
|
|
222
|
+
return nil
|
|
223
|
+
end
|
|
224
|
+
syncInputFromValue()
|
|
225
|
+
end, { open, syncInputFromValue, value })
|
|
226
|
+
local contextValue = React.useMemo(function()
|
|
227
|
+
return {
|
|
228
|
+
open = open,
|
|
229
|
+
setOpen = setOpen,
|
|
230
|
+
value = value,
|
|
231
|
+
setValue = setValue,
|
|
232
|
+
inputValue = inputValue,
|
|
233
|
+
setInputValue = setInputValue,
|
|
234
|
+
syncInputFromValue = syncInputFromValue,
|
|
235
|
+
disabled = disabled,
|
|
236
|
+
readOnly = readOnly,
|
|
237
|
+
required = required,
|
|
238
|
+
loop = loop,
|
|
239
|
+
filterFn = filterFn,
|
|
240
|
+
triggerRef = triggerRef,
|
|
241
|
+
inputRef = inputRef,
|
|
242
|
+
contentRef = contentRef,
|
|
243
|
+
registerItem = registerItem,
|
|
244
|
+
getOrderedItems = resolveOrderedItems,
|
|
245
|
+
getFilteredItems = getFilteredItems,
|
|
246
|
+
getItemText = getItemText,
|
|
247
|
+
}
|
|
248
|
+
end, { disabled, filterFn, getFilteredItems, getItemText, inputValue, loop, open, readOnly, registerItem, required, resolveOrderedItems, setInputValue, setOpen, setValue, syncInputFromValue, value })
|
|
249
|
+
return React.createElement(ComboboxContextProvider, {
|
|
250
|
+
value = contextValue,
|
|
251
|
+
}, props.children)
|
|
252
|
+
end
|
|
253
|
+
return {
|
|
254
|
+
ComboboxRoot = ComboboxRoot,
|
|
255
|
+
Combobox = ComboboxRoot,
|
|
256
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
|
+
local React = _core.React
|
|
5
|
+
local Slot = _core.Slot
|
|
6
|
+
local function ComboboxSeparator(props)
|
|
7
|
+
if props.asChild then
|
|
8
|
+
local child = props.children
|
|
9
|
+
if not child then
|
|
10
|
+
error("[ComboboxSeparator] `asChild` requires a child element.")
|
|
11
|
+
end
|
|
12
|
+
return React.createElement(Slot, nil, child)
|
|
13
|
+
end
|
|
14
|
+
return React.createElement("frame", {
|
|
15
|
+
BackgroundColor3 = Color3.fromRGB(78, 86, 104),
|
|
16
|
+
BorderSizePixel = 0,
|
|
17
|
+
Size = UDim2.fromOffset(220, 1),
|
|
18
|
+
}, props.children)
|
|
19
|
+
end
|
|
20
|
+
return {
|
|
21
|
+
ComboboxSeparator = ComboboxSeparator,
|
|
22
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
|
+
local React = _core.React
|
|
5
|
+
local Slot = _core.Slot
|
|
6
|
+
local useComboboxContext = TS.import(script, script.Parent, "context").useComboboxContext
|
|
7
|
+
local function toGuiObject(instance)
|
|
8
|
+
if not instance or not instance:IsA("GuiObject") then
|
|
9
|
+
return nil
|
|
10
|
+
end
|
|
11
|
+
return instance
|
|
12
|
+
end
|
|
13
|
+
local function ComboboxTrigger(props)
|
|
14
|
+
local comboboxContext = useComboboxContext()
|
|
15
|
+
local disabled = comboboxContext.disabled or props.disabled == true
|
|
16
|
+
local setTriggerRef = React.useCallback(function(instance)
|
|
17
|
+
comboboxContext.triggerRef.current = toGuiObject(instance)
|
|
18
|
+
end, { comboboxContext.triggerRef })
|
|
19
|
+
local handleActivated = React.useCallback(function()
|
|
20
|
+
if disabled then
|
|
21
|
+
return nil
|
|
22
|
+
end
|
|
23
|
+
comboboxContext.setOpen(not comboboxContext.open)
|
|
24
|
+
end, { comboboxContext, disabled })
|
|
25
|
+
local handleInputBegan = React.useCallback(function(_rbx, inputObject)
|
|
26
|
+
if disabled then
|
|
27
|
+
return nil
|
|
28
|
+
end
|
|
29
|
+
local keyCode = inputObject.KeyCode
|
|
30
|
+
if keyCode == Enum.KeyCode.Return or keyCode == Enum.KeyCode.Space then
|
|
31
|
+
comboboxContext.setOpen(not comboboxContext.open)
|
|
32
|
+
return nil
|
|
33
|
+
end
|
|
34
|
+
if keyCode == Enum.KeyCode.Down or keyCode == Enum.KeyCode.Up then
|
|
35
|
+
comboboxContext.setOpen(true)
|
|
36
|
+
end
|
|
37
|
+
end, { comboboxContext, disabled })
|
|
38
|
+
local eventHandlers = React.useMemo(function()
|
|
39
|
+
return {
|
|
40
|
+
Activated = handleActivated,
|
|
41
|
+
InputBegan = handleInputBegan,
|
|
42
|
+
}
|
|
43
|
+
end, { handleActivated, handleInputBegan })
|
|
44
|
+
if props.asChild then
|
|
45
|
+
local child = props.children
|
|
46
|
+
if not child then
|
|
47
|
+
error("[ComboboxTrigger] `asChild` requires a child element.")
|
|
48
|
+
end
|
|
49
|
+
return React.createElement(Slot, {
|
|
50
|
+
Active = not disabled,
|
|
51
|
+
Event = eventHandlers,
|
|
52
|
+
Selectable = not disabled,
|
|
53
|
+
ref = setTriggerRef,
|
|
54
|
+
}, child)
|
|
55
|
+
end
|
|
56
|
+
return React.createElement("textbutton", {
|
|
57
|
+
Active = not disabled,
|
|
58
|
+
AutoButtonColor = false,
|
|
59
|
+
BackgroundColor3 = Color3.fromRGB(41, 48, 63),
|
|
60
|
+
BorderSizePixel = 0,
|
|
61
|
+
Event = eventHandlers,
|
|
62
|
+
Selectable = not disabled,
|
|
63
|
+
Size = UDim2.fromOffset(220, 36),
|
|
64
|
+
Text = "Combobox",
|
|
65
|
+
TextColor3 = if disabled then Color3.fromRGB(140, 148, 164) else Color3.fromRGB(235, 241, 248),
|
|
66
|
+
TextSize = 15,
|
|
67
|
+
ref = setTriggerRef,
|
|
68
|
+
}, props.children)
|
|
69
|
+
end
|
|
70
|
+
return {
|
|
71
|
+
ComboboxTrigger = ComboboxTrigger,
|
|
72
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
|
+
local React = _core.React
|
|
5
|
+
local Slot = _core.Slot
|
|
6
|
+
local useComboboxContext = TS.import(script, script.Parent, "context").useComboboxContext
|
|
7
|
+
local function ComboboxValue(props)
|
|
8
|
+
local comboboxContext = useComboboxContext()
|
|
9
|
+
local selectedValue = comboboxContext.value
|
|
10
|
+
local hasValue = selectedValue ~= nil
|
|
11
|
+
local resolvedText = React.useMemo(function()
|
|
12
|
+
if not hasValue or selectedValue == nil then
|
|
13
|
+
local _condition = props.placeholder
|
|
14
|
+
if _condition == nil then
|
|
15
|
+
_condition = ""
|
|
16
|
+
end
|
|
17
|
+
return _condition
|
|
18
|
+
end
|
|
19
|
+
local _condition = comboboxContext.getItemText(selectedValue)
|
|
20
|
+
if _condition == nil then
|
|
21
|
+
_condition = selectedValue
|
|
22
|
+
end
|
|
23
|
+
return _condition
|
|
24
|
+
end, { comboboxContext, hasValue, props.placeholder, selectedValue })
|
|
25
|
+
if props.asChild then
|
|
26
|
+
local child = props.children
|
|
27
|
+
if not child then
|
|
28
|
+
error("[ComboboxValue] `asChild` requires a child element.")
|
|
29
|
+
end
|
|
30
|
+
return React.createElement(Slot, {
|
|
31
|
+
Name = "ComboboxValue",
|
|
32
|
+
Text = resolvedText,
|
|
33
|
+
}, child)
|
|
34
|
+
end
|
|
35
|
+
return React.createElement("textlabel", {
|
|
36
|
+
BackgroundTransparency = 1,
|
|
37
|
+
BorderSizePixel = 0,
|
|
38
|
+
Size = UDim2.fromOffset(200, 20),
|
|
39
|
+
Text = resolvedText,
|
|
40
|
+
TextColor3 = if hasValue then Color3.fromRGB(235, 240, 248) else Color3.fromRGB(153, 161, 177),
|
|
41
|
+
TextSize = 14,
|
|
42
|
+
TextXAlignment = Enum.TextXAlignment.Left,
|
|
43
|
+
})
|
|
44
|
+
end
|
|
45
|
+
return {
|
|
46
|
+
ComboboxValue = ComboboxValue,
|
|
47
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local createStrictContext = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out).createStrictContext
|
|
4
|
+
local _binding = createStrictContext("Combobox")
|
|
5
|
+
local ComboboxContextProvider = _binding[1]
|
|
6
|
+
local useComboboxContext = _binding[2]
|
|
7
|
+
return {
|
|
8
|
+
ComboboxContextProvider = ComboboxContextProvider,
|
|
9
|
+
useComboboxContext = useComboboxContext,
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ComboboxOption = {
|
|
2
|
+
value: string;
|
|
3
|
+
disabled: boolean;
|
|
4
|
+
textValue: string;
|
|
5
|
+
};
|
|
6
|
+
export type ComboboxFilterFn = (itemText: string, query: string) => boolean;
|
|
7
|
+
export declare function defaultComboboxFilter(itemText: string, query: string): boolean;
|
|
8
|
+
export declare function resolveForcedComboboxValue(currentValue: string | undefined, options: Array<ComboboxOption>): string | undefined;
|
|
9
|
+
export declare function resolveComboboxInputValue(selectedValue: string | undefined, options: Array<ComboboxOption>, placeholder?: string): string;
|
|
10
|
+
export declare function filterComboboxOptions(options: Array<ComboboxOption>, query: string, filterFn?: ComboboxFilterFn): ComboboxOption[];
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local function defaultComboboxFilter(itemText, query)
|
|
3
|
+
local normalizedItemText = string.lower(itemText)
|
|
4
|
+
local normalizedQuery = string.lower(query)
|
|
5
|
+
return { string.find(normalizedItemText, normalizedQuery, 1, true) } ~= nil
|
|
6
|
+
end
|
|
7
|
+
local function resolveForcedComboboxValue(currentValue, options)
|
|
8
|
+
-- ▼ ReadonlyArray.filter ▼
|
|
9
|
+
local _newValue = {}
|
|
10
|
+
local _callback = function(option)
|
|
11
|
+
return not option.disabled
|
|
12
|
+
end
|
|
13
|
+
local _length = 0
|
|
14
|
+
for _k, _v in options do
|
|
15
|
+
if _callback(_v, _k - 1, options) == true then
|
|
16
|
+
_length += 1
|
|
17
|
+
_newValue[_length] = _v
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
-- ▲ ReadonlyArray.filter ▲
|
|
21
|
+
local enabled = _newValue
|
|
22
|
+
if #enabled == 0 then
|
|
23
|
+
return nil
|
|
24
|
+
end
|
|
25
|
+
if currentValue == nil then
|
|
26
|
+
local _result = enabled[1]
|
|
27
|
+
if _result ~= nil then
|
|
28
|
+
_result = _result.value
|
|
29
|
+
end
|
|
30
|
+
return _result
|
|
31
|
+
end
|
|
32
|
+
-- ▼ ReadonlyArray.find ▼
|
|
33
|
+
local _callback_1 = function(option)
|
|
34
|
+
return option.value == currentValue
|
|
35
|
+
end
|
|
36
|
+
local _result
|
|
37
|
+
for _i, _v in enabled do
|
|
38
|
+
if _callback_1(_v, _i - 1, enabled) == true then
|
|
39
|
+
_result = _v
|
|
40
|
+
break
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
-- ▲ ReadonlyArray.find ▲
|
|
44
|
+
local selected = _result
|
|
45
|
+
if selected then
|
|
46
|
+
return selected.value
|
|
47
|
+
end
|
|
48
|
+
local _result_1 = enabled[1]
|
|
49
|
+
if _result_1 ~= nil then
|
|
50
|
+
_result_1 = _result_1.value
|
|
51
|
+
end
|
|
52
|
+
return _result_1
|
|
53
|
+
end
|
|
54
|
+
local function resolveComboboxInputValue(selectedValue, options, placeholder)
|
|
55
|
+
if placeholder == nil then
|
|
56
|
+
placeholder = ""
|
|
57
|
+
end
|
|
58
|
+
if selectedValue == nil then
|
|
59
|
+
return placeholder
|
|
60
|
+
end
|
|
61
|
+
-- ▼ ReadonlyArray.find ▼
|
|
62
|
+
local _callback = function(option)
|
|
63
|
+
return option.value == selectedValue and not option.disabled
|
|
64
|
+
end
|
|
65
|
+
local _result
|
|
66
|
+
for _i, _v in options do
|
|
67
|
+
if _callback(_v, _i - 1, options) == true then
|
|
68
|
+
_result = _v
|
|
69
|
+
break
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
-- ▲ ReadonlyArray.find ▲
|
|
73
|
+
local selected = _result
|
|
74
|
+
if not selected then
|
|
75
|
+
return placeholder
|
|
76
|
+
end
|
|
77
|
+
return selected.textValue
|
|
78
|
+
end
|
|
79
|
+
local function filterComboboxOptions(options, query, filterFn)
|
|
80
|
+
if filterFn == nil then
|
|
81
|
+
filterFn = defaultComboboxFilter
|
|
82
|
+
end
|
|
83
|
+
-- ▼ ReadonlyArray.filter ▼
|
|
84
|
+
local _newValue = {}
|
|
85
|
+
local _callback = function(option)
|
|
86
|
+
return filterFn(option.textValue, query)
|
|
87
|
+
end
|
|
88
|
+
local _length = 0
|
|
89
|
+
for _k, _v in options do
|
|
90
|
+
if _callback(_v, _k - 1, options) == true then
|
|
91
|
+
_length += 1
|
|
92
|
+
_newValue[_length] = _v
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
-- ▲ ReadonlyArray.filter ▲
|
|
96
|
+
return _newValue
|
|
97
|
+
end
|
|
98
|
+
return {
|
|
99
|
+
defaultComboboxFilter = defaultComboboxFilter,
|
|
100
|
+
resolveForcedComboboxValue = resolveForcedComboboxValue,
|
|
101
|
+
resolveComboboxInputValue = resolveComboboxInputValue,
|
|
102
|
+
filterComboboxOptions = filterComboboxOptions,
|
|
103
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { LayerInteractEvent } from "@lattice-ui/layer";
|
|
2
|
+
import type { PopperPlacement } from "@lattice-ui/popper";
|
|
3
|
+
import type React from "@rbxts/react";
|
|
4
|
+
export type ComboboxFilterFn = (itemText: string, query: string) => boolean;
|
|
5
|
+
export type ComboboxSetOpen = (open: boolean) => void;
|
|
6
|
+
export type ComboboxSetValue = (value: string) => void;
|
|
7
|
+
export type ComboboxSetInputValue = (inputValue: string) => void;
|
|
8
|
+
export type ComboboxItemRegistration = {
|
|
9
|
+
id: number;
|
|
10
|
+
value: string;
|
|
11
|
+
order: number;
|
|
12
|
+
getNode: () => GuiObject | undefined;
|
|
13
|
+
getDisabled: () => boolean;
|
|
14
|
+
getTextValue: () => string;
|
|
15
|
+
};
|
|
16
|
+
export type ComboboxContextValue = {
|
|
17
|
+
open: boolean;
|
|
18
|
+
setOpen: ComboboxSetOpen;
|
|
19
|
+
value?: string;
|
|
20
|
+
setValue: ComboboxSetValue;
|
|
21
|
+
inputValue: string;
|
|
22
|
+
setInputValue: ComboboxSetInputValue;
|
|
23
|
+
syncInputFromValue: () => void;
|
|
24
|
+
disabled: boolean;
|
|
25
|
+
readOnly: boolean;
|
|
26
|
+
required: boolean;
|
|
27
|
+
loop: boolean;
|
|
28
|
+
filterFn: ComboboxFilterFn;
|
|
29
|
+
triggerRef: React.MutableRefObject<GuiObject | undefined>;
|
|
30
|
+
inputRef: React.MutableRefObject<TextBox | undefined>;
|
|
31
|
+
contentRef: React.MutableRefObject<GuiObject | undefined>;
|
|
32
|
+
registerItem: (item: ComboboxItemRegistration) => () => void;
|
|
33
|
+
getOrderedItems: () => Array<ComboboxItemRegistration>;
|
|
34
|
+
getFilteredItems: () => Array<ComboboxItemRegistration>;
|
|
35
|
+
getItemText: (value: string) => string | undefined;
|
|
36
|
+
};
|
|
37
|
+
export type ComboboxProps = {
|
|
38
|
+
value?: string;
|
|
39
|
+
defaultValue?: string;
|
|
40
|
+
onValueChange?: (value: string) => void;
|
|
41
|
+
inputValue?: string;
|
|
42
|
+
defaultInputValue?: string;
|
|
43
|
+
onInputValueChange?: (inputValue: string) => void;
|
|
44
|
+
open?: boolean;
|
|
45
|
+
defaultOpen?: boolean;
|
|
46
|
+
onOpenChange?: (open: boolean) => void;
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
readOnly?: boolean;
|
|
49
|
+
required?: boolean;
|
|
50
|
+
loop?: boolean;
|
|
51
|
+
filterFn?: ComboboxFilterFn;
|
|
52
|
+
children?: React.ReactNode;
|
|
53
|
+
};
|
|
54
|
+
export type ComboboxTriggerProps = {
|
|
55
|
+
asChild?: boolean;
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
children?: React.ReactElement;
|
|
58
|
+
};
|
|
59
|
+
export type ComboboxInputProps = {
|
|
60
|
+
asChild?: boolean;
|
|
61
|
+
disabled?: boolean;
|
|
62
|
+
readOnly?: boolean;
|
|
63
|
+
placeholder?: string;
|
|
64
|
+
children?: React.ReactElement;
|
|
65
|
+
};
|
|
66
|
+
export type ComboboxValueProps = {
|
|
67
|
+
asChild?: boolean;
|
|
68
|
+
placeholder?: string;
|
|
69
|
+
children?: React.ReactElement;
|
|
70
|
+
};
|
|
71
|
+
export type ComboboxPortalProps = {
|
|
72
|
+
container?: BasePlayerGui;
|
|
73
|
+
displayOrderBase?: number;
|
|
74
|
+
children?: React.ReactNode;
|
|
75
|
+
};
|
|
76
|
+
export type ComboboxContentProps = {
|
|
77
|
+
asChild?: boolean;
|
|
78
|
+
forceMount?: boolean;
|
|
79
|
+
placement?: PopperPlacement;
|
|
80
|
+
offset?: Vector2;
|
|
81
|
+
padding?: number;
|
|
82
|
+
onEscapeKeyDown?: (event: LayerInteractEvent) => void;
|
|
83
|
+
onPointerDownOutside?: (event: LayerInteractEvent) => void;
|
|
84
|
+
onInteractOutside?: (event: LayerInteractEvent) => void;
|
|
85
|
+
children?: React.ReactNode;
|
|
86
|
+
};
|
|
87
|
+
export type ComboboxItemProps = {
|
|
88
|
+
value: string;
|
|
89
|
+
textValue?: string;
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
asChild?: boolean;
|
|
92
|
+
children?: React.ReactElement;
|
|
93
|
+
};
|
|
94
|
+
export type ComboboxSeparatorProps = {
|
|
95
|
+
asChild?: boolean;
|
|
96
|
+
children?: React.ReactElement;
|
|
97
|
+
};
|
|
98
|
+
export type ComboboxGroupProps = {
|
|
99
|
+
asChild?: boolean;
|
|
100
|
+
children?: React.ReactElement;
|
|
101
|
+
};
|
|
102
|
+
export type ComboboxLabelProps = {
|
|
103
|
+
asChild?: boolean;
|
|
104
|
+
children?: React.ReactElement;
|
|
105
|
+
};
|
package/out/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComboboxContent } from "./Combobox/ComboboxContent";
|
|
2
|
+
import { ComboboxGroup } from "./Combobox/ComboboxGroup";
|
|
3
|
+
import { ComboboxInput } from "./Combobox/ComboboxInput";
|
|
4
|
+
import { ComboboxItem } from "./Combobox/ComboboxItem";
|
|
5
|
+
import { ComboboxLabel } from "./Combobox/ComboboxLabel";
|
|
6
|
+
import { ComboboxPortal } from "./Combobox/ComboboxPortal";
|
|
7
|
+
import { ComboboxRoot } from "./Combobox/ComboboxRoot";
|
|
8
|
+
import { ComboboxSeparator } from "./Combobox/ComboboxSeparator";
|
|
9
|
+
import { ComboboxTrigger } from "./Combobox/ComboboxTrigger";
|
|
10
|
+
import { ComboboxValue } from "./Combobox/ComboboxValue";
|
|
11
|
+
export declare const Combobox: {
|
|
12
|
+
readonly Root: typeof ComboboxRoot;
|
|
13
|
+
readonly Trigger: typeof ComboboxTrigger;
|
|
14
|
+
readonly Input: typeof ComboboxInput;
|
|
15
|
+
readonly Value: typeof ComboboxValue;
|
|
16
|
+
readonly Portal: typeof ComboboxPortal;
|
|
17
|
+
readonly Content: typeof ComboboxContent;
|
|
18
|
+
readonly Item: typeof ComboboxItem;
|
|
19
|
+
readonly Group: typeof ComboboxGroup;
|
|
20
|
+
readonly Label: typeof ComboboxLabel;
|
|
21
|
+
readonly Separator: typeof ComboboxSeparator;
|
|
22
|
+
};
|
|
23
|
+
export { defaultComboboxFilter, filterComboboxOptions, resolveComboboxInputValue, resolveForcedComboboxValue, } from "./Combobox/logic";
|
|
24
|
+
export type { ComboboxContentProps, ComboboxContextValue, ComboboxFilterFn, ComboboxGroupProps, ComboboxInputProps, ComboboxItemProps, ComboboxItemRegistration, ComboboxLabelProps, ComboboxPortalProps, ComboboxProps, ComboboxSeparatorProps, ComboboxSetInputValue, ComboboxSetOpen, ComboboxSetValue, ComboboxTriggerProps, ComboboxValueProps, } from "./Combobox/types";
|