@rbxts/centurion-ui 1.0.8 → 2.0.0-rc.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/README.md +60 -15
- package/centurion.luau +10 -0
- package/package.json +13 -23
- package/src/analyse/cursor.luau +25 -0
- package/src/analyse/highlight.luau +91 -0
- package/src/analyse/init.luau +318 -0
- package/src/analyse/leventine.luau +298 -0
- package/src/analyse/match.luau +39 -0
- package/src/analyse/suggest.luau +41 -0
- package/src/app/header.luau +128 -0
- package/src/app/history.luau +258 -0
- package/src/app/init.luau +699 -0
- package/src/app/suggestions.luau +419 -0
- package/src/button.luau +13 -0
- package/src/components/background.luau +37 -0
- package/src/components/container.luau +33 -0
- package/src/components/corner.luau +11 -0
- package/src/components/divider.luau +28 -0
- package/src/components/flex.luau +108 -0
- package/src/components/gap.luau +25 -0
- package/src/components/image.luau +33 -0
- package/src/components/padding.luau +59 -0
- package/src/components/stroke.luau +20 -0
- package/src/components/text.luau +57 -0
- package/src/components/textbox.luau +186 -0
- package/src/fade.luau +23 -0
- package/src/init.luau +142 -0
- package/src/input.luau +16 -0
- package/src/px.luau +68 -0
- package/src/rich.luau +14 -0
- package/src/state.luau +33 -0
- package/src/theme.luau +70 -0
- package/src/ts/index.d.ts +60 -0
- package/src/ts/init.luau +5 -0
- package/src/types.luau +85 -0
- package/vide/init.luau +8 -0
- package/vide/src/action.luau +25 -0
- package/vide/src/apply.luau +162 -0
- package/vide/src/batch.luau +23 -0
- package/vide/src/branch.luau +40 -0
- package/vide/src/changed.luau +18 -0
- package/vide/src/cleanup.luau +43 -0
- package/vide/src/context.luau +74 -0
- package/vide/src/create.luau +107 -0
- package/vide/src/defaults.luau +113 -0
- package/vide/src/derive.luau +18 -0
- package/vide/src/effect.luau +12 -0
- package/vide/src/flags.luau +12 -0
- package/vide/src/graph.luau +321 -0
- package/vide/src/implicit_effect.luau +125 -0
- package/vide/src/indexes.luau +121 -0
- package/vide/src/init.luau +10 -0
- package/vide/src/lib.luau +120 -0
- package/vide/src/mount.luau +11 -0
- package/vide/src/read.luau +5 -0
- package/vide/src/root.luau +35 -0
- package/vide/src/show.luau +36 -0
- package/vide/src/source.luau +31 -0
- package/vide/src/spring.luau +328 -0
- package/vide/src/switch.luau +114 -0
- package/vide/src/timeout.luau +27 -0
- package/vide/src/untrack.luau +25 -0
- package/vide/src/values.luau +131 -0
- package/out/app/centurion-app.d.ts +0 -3
- package/out/app/centurion-app.luau +0 -86
- package/out/app/index.d.ts +0 -32
- package/out/app/init.luau +0 -105
- package/out/components/history/history-line.d.ts +0 -9
- package/out/components/history/history-line.luau +0 -88
- package/out/components/history/history-list.d.ts +0 -11
- package/out/components/history/history-list.luau +0 -67
- package/out/components/history/index.d.ts +0 -1
- package/out/components/history/init.luau +0 -7
- package/out/components/index.d.ts +0 -2
- package/out/components/init.luau +0 -10
- package/out/components/suggestions/badge.d.ts +0 -16
- package/out/components/suggestions/badge.luau +0 -40
- package/out/components/suggestions/index.d.ts +0 -1
- package/out/components/suggestions/init.luau +0 -7
- package/out/components/suggestions/main-suggestion.d.ts +0 -9
- package/out/components/suggestions/main-suggestion.luau +0 -232
- package/out/components/suggestions/suggestion-list.d.ts +0 -8
- package/out/components/suggestions/suggestion-list.luau +0 -96
- package/out/components/suggestions/suggestions.d.ts +0 -2
- package/out/components/suggestions/suggestions.luau +0 -64
- package/out/components/suggestions/types.d.ts +0 -6
- package/out/components/suggestions/types.luau +0 -2
- package/out/components/suggestions/util.d.ts +0 -1
- package/out/components/suggestions/util.luau +0 -22
- package/out/components/terminal/command.d.ts +0 -6
- package/out/components/terminal/command.luau +0 -74
- package/out/components/terminal/index.d.ts +0 -1
- package/out/components/terminal/init.luau +0 -7
- package/out/components/terminal/suggestion.d.ts +0 -26
- package/out/components/terminal/suggestion.luau +0 -205
- package/out/components/terminal/terminal-text-field/index.d.ts +0 -1
- package/out/components/terminal/terminal-text-field/init.luau +0 -7
- package/out/components/terminal/terminal-text-field/suggestion.d.ts +0 -5
- package/out/components/terminal/terminal-text-field/suggestion.luau +0 -124
- package/out/components/terminal/terminal-text-field/terminal-text-field.d.ts +0 -13
- package/out/components/terminal/terminal-text-field/terminal-text-field.luau +0 -278
- package/out/components/terminal/terminal.d.ts +0 -2
- package/out/components/terminal/terminal.luau +0 -304
- package/out/components/ui/frame.d.ts +0 -17
- package/out/components/ui/frame.luau +0 -32
- package/out/components/ui/group.d.ts +0 -15
- package/out/components/ui/group.luau +0 -29
- package/out/components/ui/layer.d.ts +0 -8
- package/out/components/ui/layer.luau +0 -26
- package/out/components/ui/outline.d.ts +0 -15
- package/out/components/ui/outline.luau +0 -116
- package/out/components/ui/padding.d.ts +0 -10
- package/out/components/ui/padding.luau +0 -19
- package/out/components/ui/scrolling-frame.d.ts +0 -14
- package/out/components/ui/scrolling-frame.luau +0 -44
- package/out/components/ui/text-field.d.ts +0 -12
- package/out/components/ui/text-field.luau +0 -60
- package/out/components/ui/text.d.ts +0 -17
- package/out/components/ui/text.luau +0 -61
- package/out/constants/options.d.ts +0 -2
- package/out/constants/options.luau +0 -27
- package/out/constants/text.d.ts +0 -3
- package/out/constants/text.luau +0 -9
- package/out/constants/util.d.ts +0 -1
- package/out/constants/util.luau +0 -7
- package/out/hooks/use-client.d.ts +0 -2
- package/out/hooks/use-client.luau +0 -17
- package/out/hooks/use-event.d.ts +0 -14
- package/out/hooks/use-event.luau +0 -58
- package/out/hooks/use-px.d.ts +0 -19
- package/out/hooks/use-px.luau +0 -78
- package/out/index.d.ts +0 -2
- package/out/init.luau +0 -10
- package/out/palette.d.ts +0 -47
- package/out/palette.luau +0 -42
- package/out/store.d.ts +0 -12
- package/out/store.luau +0 -26
- package/out/types.d.ts +0 -44
- package/out/types.luau +0 -2
- package/out/utils/string.d.ts +0 -5
- package/out/utils/string.luau +0 -25
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
local background = require("../components/background")
|
|
2
|
+
local button_name = require("../button")
|
|
3
|
+
local centurion = require("../../centurion")
|
|
4
|
+
local container = require("../components/container")
|
|
5
|
+
local corner = require("../components/corner")
|
|
6
|
+
local divider = require("../components/divider")
|
|
7
|
+
local fade = require("../fade")
|
|
8
|
+
local flex = require("../components/flex")
|
|
9
|
+
local padding = require("../components/padding")
|
|
10
|
+
local preferred_input = require("../input")
|
|
11
|
+
local px = require("../px")
|
|
12
|
+
local rich = require("../rich")
|
|
13
|
+
local state = require("../state")
|
|
14
|
+
local stroke = require("../components/stroke")
|
|
15
|
+
local text = require("../components/text")
|
|
16
|
+
local theme = require("../theme")
|
|
17
|
+
local types = require("../types")
|
|
18
|
+
local vide = require("../../vide")
|
|
19
|
+
|
|
20
|
+
local create = vide.create
|
|
21
|
+
local derive = vide.derive
|
|
22
|
+
local indexes = vide.indexes
|
|
23
|
+
local show = vide.show
|
|
24
|
+
local source = vide.source
|
|
25
|
+
local spring = vide.spring
|
|
26
|
+
|
|
27
|
+
export type Suggestions = {
|
|
28
|
+
read analysis: () -> types.AnalysisResult,
|
|
29
|
+
read selected_suggestion: () -> number,
|
|
30
|
+
read on_select: (suggestion: types.AnalysisSuggestion) -> (),
|
|
31
|
+
read order: number?,
|
|
32
|
+
|
|
33
|
+
[number]: unknown,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
-- e.g. <name: type>, [name: type] if optional, <name: type...> if it takes the rest of the input
|
|
37
|
+
local function format_argument(arg: centurion.Argument): string
|
|
38
|
+
local label = `{arg.name}: {arg.type}`
|
|
39
|
+
|
|
40
|
+
local num_args = arg.num_args
|
|
41
|
+
if num_args == "rest" then
|
|
42
|
+
label ..= "..."
|
|
43
|
+
elseif typeof(num_args) == "number" and num_args > 1 then
|
|
44
|
+
label ..= ` x{num_args}`
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
return if arg.optional then `[{label}]` else `<{label}>`
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
-- small filled label, e.g. the type of an argument
|
|
51
|
+
local function pill(props: { text: () -> string, color: () -> Color3, order: number? })
|
|
52
|
+
return background {
|
|
53
|
+
auto = "XY",
|
|
54
|
+
order = props.order,
|
|
55
|
+
color = props.color,
|
|
56
|
+
|
|
57
|
+
corner(px(4)),
|
|
58
|
+
padding { x = px(6), y = px(2) },
|
|
59
|
+
|
|
60
|
+
text {
|
|
61
|
+
auto = "XY",
|
|
62
|
+
text = props.text,
|
|
63
|
+
text_size = px(state.subtext_size),
|
|
64
|
+
text_style = "bg",
|
|
65
|
+
weight = Enum.FontWeight.Bold,
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
local function suggestion_row(value: () -> types.AnalysisSuggestion, i: number, props: Suggestions)
|
|
71
|
+
local function selected()
|
|
72
|
+
return props.selected_suggestion() == i
|
|
73
|
+
end
|
|
74
|
+
local hovered = source(false)
|
|
75
|
+
|
|
76
|
+
return create "TextButton" {
|
|
77
|
+
AutomaticSize = Enum.AutomaticSize.XY,
|
|
78
|
+
AutoButtonColor = false,
|
|
79
|
+
BackgroundColor3 = function()
|
|
80
|
+
return state.theme().surface
|
|
81
|
+
end,
|
|
82
|
+
BackgroundTransparency = fade.fade(spring(function()
|
|
83
|
+
if selected() then
|
|
84
|
+
return state.transparency()
|
|
85
|
+
elseif hovered() then
|
|
86
|
+
return 1 - (1 - state.transparency()) * 0.5
|
|
87
|
+
end
|
|
88
|
+
return 1
|
|
89
|
+
end, 0.1)),
|
|
90
|
+
LayoutOrder = i,
|
|
91
|
+
Text = "",
|
|
92
|
+
|
|
93
|
+
MouseEnter = function()
|
|
94
|
+
hovered(true)
|
|
95
|
+
end,
|
|
96
|
+
MouseLeave = function()
|
|
97
|
+
hovered(false)
|
|
98
|
+
end,
|
|
99
|
+
Activated = function()
|
|
100
|
+
props.on_select(value())
|
|
101
|
+
end,
|
|
102
|
+
|
|
103
|
+
corner(px(4)),
|
|
104
|
+
padding { x = px(8), y = px(5) },
|
|
105
|
+
flex():column():vertical("center"):between("horizontal"),
|
|
106
|
+
|
|
107
|
+
container {
|
|
108
|
+
auto = "XY",
|
|
109
|
+
order = 1,
|
|
110
|
+
|
|
111
|
+
flex():column():vertical("center"),
|
|
112
|
+
|
|
113
|
+
-- marks the suggestion Tab will complete
|
|
114
|
+
text {
|
|
115
|
+
size = px(UDim2.fromOffset(18, 0)),
|
|
116
|
+
auto = "Y",
|
|
117
|
+
order = 1,
|
|
118
|
+
text = ">",
|
|
119
|
+
text_style = "highlight",
|
|
120
|
+
weight = Enum.FontWeight.Bold,
|
|
121
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
122
|
+
transparency = spring(function()
|
|
123
|
+
return if selected() then 0 else 1
|
|
124
|
+
end, 0.1),
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
text {
|
|
128
|
+
auto = "XY",
|
|
129
|
+
order = 2,
|
|
130
|
+
-- characters matching the input are emphasised
|
|
131
|
+
text = function()
|
|
132
|
+
local suggestion = value()
|
|
133
|
+
local name = suggestion.name
|
|
134
|
+
local highlight = state.theme().highlight
|
|
135
|
+
|
|
136
|
+
local out = {}
|
|
137
|
+
local pos = 1
|
|
138
|
+
for _, range in suggestion.matches do
|
|
139
|
+
table.insert(out, rich.escape(name:sub(pos, range.x - 1)))
|
|
140
|
+
table.insert(out, `<b>{rich.color(rich.escape(name:sub(range.x, range.y)), highlight)}</b>`)
|
|
141
|
+
pos = range.y + 1
|
|
142
|
+
end
|
|
143
|
+
table.insert(out, rich.escape(name:sub(pos)))
|
|
144
|
+
|
|
145
|
+
return table.concat(out)
|
|
146
|
+
end,
|
|
147
|
+
rich_text = true,
|
|
148
|
+
text_style = function()
|
|
149
|
+
return if selected() then "normal" else "subtext"
|
|
150
|
+
end,
|
|
151
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
show(function()
|
|
156
|
+
return value().description ~= nil
|
|
157
|
+
end, function()
|
|
158
|
+
return text {
|
|
159
|
+
auto = "XY",
|
|
160
|
+
order = 2,
|
|
161
|
+
text = function()
|
|
162
|
+
return value().description or ""
|
|
163
|
+
end,
|
|
164
|
+
text_size = px(state.subtext_size),
|
|
165
|
+
text_style = "subtext",
|
|
166
|
+
xalignment = Enum.TextXAlignment.Right,
|
|
167
|
+
|
|
168
|
+
-- keeps the description away from the name
|
|
169
|
+
padding { left = px(32) },
|
|
170
|
+
}
|
|
171
|
+
end),
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
local function suggestions(props: Suggestions)
|
|
176
|
+
local usage = derive(function()
|
|
177
|
+
local analysis = props.analysis()
|
|
178
|
+
if analysis.argument == nil or analysis.command == nil then
|
|
179
|
+
return nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
local cmd = centurion.registry.commands[analysis.command]
|
|
183
|
+
if cmd == nil or cmd.arguments == nil then
|
|
184
|
+
return nil
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
local args: { centurion.Argument } = { cmd.arguments() }
|
|
188
|
+
return {
|
|
189
|
+
command = analysis.command,
|
|
190
|
+
args = args,
|
|
191
|
+
index = analysis.argument.index,
|
|
192
|
+
}
|
|
193
|
+
end)
|
|
194
|
+
|
|
195
|
+
local arg = derive(function()
|
|
196
|
+
local current = usage()
|
|
197
|
+
return current and current.args[current.index]
|
|
198
|
+
end)
|
|
199
|
+
|
|
200
|
+
local failed = derive(function()
|
|
201
|
+
return not props.analysis().result.success
|
|
202
|
+
end)
|
|
203
|
+
|
|
204
|
+
local has_suggestions = derive(function()
|
|
205
|
+
return #props.analysis().suggestions > 0
|
|
206
|
+
end)
|
|
207
|
+
|
|
208
|
+
local input = preferred_input()
|
|
209
|
+
|
|
210
|
+
-- the sections above the list, which are divided from it when both are shown
|
|
211
|
+
local has_details = derive(function()
|
|
212
|
+
return failed() or arg() ~= nil
|
|
213
|
+
end)
|
|
214
|
+
|
|
215
|
+
return background {
|
|
216
|
+
auto = "XY",
|
|
217
|
+
order = props.order,
|
|
218
|
+
color = function()
|
|
219
|
+
return state.theme().background
|
|
220
|
+
end,
|
|
221
|
+
transparency = state.transparency,
|
|
222
|
+
|
|
223
|
+
corner(px(8)),
|
|
224
|
+
stroke {
|
|
225
|
+
color = function()
|
|
226
|
+
return theme.border(state.theme())
|
|
227
|
+
end,
|
|
228
|
+
},
|
|
229
|
+
create "UISizeConstraint" {
|
|
230
|
+
MinSize = function()
|
|
231
|
+
return Vector2.new(px.convert(320), 0)
|
|
232
|
+
end,
|
|
233
|
+
},
|
|
234
|
+
flex():row():fill("horizontal"),
|
|
235
|
+
|
|
236
|
+
-- why the input can't be run as it is
|
|
237
|
+
show(failed, function()
|
|
238
|
+
return container {
|
|
239
|
+
auto = "XY",
|
|
240
|
+
order = 1,
|
|
241
|
+
|
|
242
|
+
padding { x = px(12), y = px(8) },
|
|
243
|
+
flex():column():vertical("center"):gap(8),
|
|
244
|
+
|
|
245
|
+
pill {
|
|
246
|
+
order = 1,
|
|
247
|
+
text = function()
|
|
248
|
+
return "error"
|
|
249
|
+
end,
|
|
250
|
+
color = function()
|
|
251
|
+
return state.theme().error
|
|
252
|
+
end,
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
text {
|
|
256
|
+
auto = "XY",
|
|
257
|
+
order = 2,
|
|
258
|
+
text = function()
|
|
259
|
+
return props.analysis().result.error or ""
|
|
260
|
+
end,
|
|
261
|
+
text_size = px(state.subtext_size),
|
|
262
|
+
text_style = "error",
|
|
263
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
264
|
+
},
|
|
265
|
+
}
|
|
266
|
+
end),
|
|
267
|
+
|
|
268
|
+
-- the full signature, and details of the argument being typed
|
|
269
|
+
show(arg, function()
|
|
270
|
+
return container {
|
|
271
|
+
auto = "XY",
|
|
272
|
+
order = 2,
|
|
273
|
+
|
|
274
|
+
padding { x = px(12), y = px(8) },
|
|
275
|
+
flex():row():gap(6),
|
|
276
|
+
|
|
277
|
+
text {
|
|
278
|
+
auto = "XY",
|
|
279
|
+
order = 1,
|
|
280
|
+
text = function()
|
|
281
|
+
local current = usage()
|
|
282
|
+
if not current then
|
|
283
|
+
return ""
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
local colors = state.theme()
|
|
287
|
+
local parts = { `<b>{rich.escape(current.command)}</b>` }
|
|
288
|
+
for i, value in current.args do
|
|
289
|
+
local label = rich.escape(format_argument(value))
|
|
290
|
+
table.insert(
|
|
291
|
+
parts,
|
|
292
|
+
if i == current.index
|
|
293
|
+
then `<b>{rich.color(label, colors.highlight)}</b>`
|
|
294
|
+
else rich.color(label, colors.subtext)
|
|
295
|
+
)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
return table.concat(parts, " ")
|
|
299
|
+
end,
|
|
300
|
+
rich_text = true,
|
|
301
|
+
text_size = px(state.subtext_size),
|
|
302
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
container {
|
|
306
|
+
auto = "XY",
|
|
307
|
+
order = 2,
|
|
308
|
+
|
|
309
|
+
flex():column():vertical("center"):gap(8),
|
|
310
|
+
|
|
311
|
+
pill {
|
|
312
|
+
order = 1,
|
|
313
|
+
text = function()
|
|
314
|
+
return arg() and arg().type or ""
|
|
315
|
+
end,
|
|
316
|
+
color = function()
|
|
317
|
+
return state.theme().highlight
|
|
318
|
+
end,
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
text {
|
|
322
|
+
auto = "XY",
|
|
323
|
+
order = 2,
|
|
324
|
+
text = function()
|
|
325
|
+
return arg() and arg().name or ""
|
|
326
|
+
end,
|
|
327
|
+
weight = Enum.FontWeight.Bold,
|
|
328
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
show(function()
|
|
332
|
+
return arg() and arg().description ~= nil
|
|
333
|
+
end, function()
|
|
334
|
+
return text {
|
|
335
|
+
auto = "XY",
|
|
336
|
+
order = 3,
|
|
337
|
+
text = function()
|
|
338
|
+
return arg() and arg().description or ""
|
|
339
|
+
end,
|
|
340
|
+
text_size = px(state.subtext_size),
|
|
341
|
+
text_style = "subtext",
|
|
342
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
343
|
+
}
|
|
344
|
+
end),
|
|
345
|
+
},
|
|
346
|
+
}
|
|
347
|
+
end),
|
|
348
|
+
|
|
349
|
+
divider {
|
|
350
|
+
order = 3,
|
|
351
|
+
visible = function()
|
|
352
|
+
return has_details() and has_suggestions()
|
|
353
|
+
end,
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
show(has_suggestions, function()
|
|
357
|
+
return container {
|
|
358
|
+
auto = "XY",
|
|
359
|
+
order = 4,
|
|
360
|
+
|
|
361
|
+
padding(px(4)),
|
|
362
|
+
flex():row():fill("horizontal"),
|
|
363
|
+
|
|
364
|
+
indexes(function()
|
|
365
|
+
return props.analysis().suggestions
|
|
366
|
+
end, function(value: () -> types.AnalysisSuggestion, i)
|
|
367
|
+
return suggestion_row(value, i, props)
|
|
368
|
+
end),
|
|
369
|
+
}
|
|
370
|
+
end),
|
|
371
|
+
|
|
372
|
+
divider {
|
|
373
|
+
order = 5,
|
|
374
|
+
visible = has_suggestions,
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
show(has_suggestions, function()
|
|
378
|
+
return container {
|
|
379
|
+
auto = "XY",
|
|
380
|
+
order = 6,
|
|
381
|
+
|
|
382
|
+
padding { x = px(12), y = px(6) },
|
|
383
|
+
|
|
384
|
+
text {
|
|
385
|
+
auto = "XY",
|
|
386
|
+
text = function()
|
|
387
|
+
local key = rich.color("%s", state.theme().text)
|
|
388
|
+
if input() == Enum.PreferredInput.Touch then
|
|
389
|
+
return `<b>{key:format("Tap")}</b> a suggestion to complete it`
|
|
390
|
+
elseif input() == Enum.PreferredInput.Gamepad then
|
|
391
|
+
return table.concat({
|
|
392
|
+
`<b>{key:format(button_name(Enum.KeyCode.ButtonA))}</b> complete`,
|
|
393
|
+
`<b>{key:format("D-pad")}</b> select`,
|
|
394
|
+
`<b>{key:format(button_name(Enum.KeyCode.ButtonX))}</b> edit`,
|
|
395
|
+
`<b>{key:format(button_name(Enum.KeyCode.ButtonY))}</b> run`,
|
|
396
|
+
`<b>{key:format(button_name(Enum.KeyCode.ButtonB))}</b> close`,
|
|
397
|
+
}, " ")
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
local hints = {
|
|
401
|
+
`<b>{key:format("Tab")}</b> complete`,
|
|
402
|
+
`<b>{key:format("↑↓")}</b> select`,
|
|
403
|
+
`<b>{key:format("Enter")}</b> run`,
|
|
404
|
+
}
|
|
405
|
+
return table.concat(hints, " ")
|
|
406
|
+
end,
|
|
407
|
+
rich_text = true,
|
|
408
|
+
text_size = px(state.subtext_size),
|
|
409
|
+
text_style = "subtext",
|
|
410
|
+
xalignment = Enum.TextXAlignment.Left,
|
|
411
|
+
},
|
|
412
|
+
}
|
|
413
|
+
end),
|
|
414
|
+
|
|
415
|
+
unpack(props),
|
|
416
|
+
}
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
return suggestions
|
package/src/button.luau
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
local UserInputService = game:GetService("UserInputService")
|
|
2
|
+
|
|
3
|
+
-- name of a gamepad button for the connected controller, e.g. "A" on Xbox
|
|
4
|
+
-- and "Cross" on PlayStation
|
|
5
|
+
local function button_name(key: Enum.KeyCode): string
|
|
6
|
+
local name = UserInputService:GetStringForKeyCode(key)
|
|
7
|
+
if name == "" then
|
|
8
|
+
name = key.Name
|
|
9
|
+
end
|
|
10
|
+
return (name:gsub("^Button", ""))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
return button_name
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
local fade = require("../fade")
|
|
2
|
+
local vide = require("../../vide")
|
|
3
|
+
|
|
4
|
+
local create = vide.create
|
|
5
|
+
|
|
6
|
+
type Can<T> = T | () -> T
|
|
7
|
+
type Background = {
|
|
8
|
+
read size: Can<UDim2>?,
|
|
9
|
+
read position: Can<UDim2>?,
|
|
10
|
+
read anchor: Can<Vector2>?,
|
|
11
|
+
read color: Can<Color3>?,
|
|
12
|
+
read zindex: Can<number>?,
|
|
13
|
+
read auto: Can<Enum.AutomaticSize | "X" | "Y" | "XY">?,
|
|
14
|
+
read order: Can<number>?,
|
|
15
|
+
read transparency: Can<number>?,
|
|
16
|
+
read visible: Can<boolean>?,
|
|
17
|
+
|
|
18
|
+
[number]: unknown,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return function(props: Background)
|
|
22
|
+
return create "Frame" {
|
|
23
|
+
Size = props.size,
|
|
24
|
+
BackgroundColor3 = props.color,
|
|
25
|
+
BackgroundTransparency = fade.fade(props.transparency),
|
|
26
|
+
Position = props.position,
|
|
27
|
+
AnchorPoint = props.anchor,
|
|
28
|
+
AutomaticSize = props.auto,
|
|
29
|
+
LayoutOrder = props.order,
|
|
30
|
+
ZIndex = props.zindex,
|
|
31
|
+
Visible = props.visible,
|
|
32
|
+
|
|
33
|
+
AutoLocalize = false,
|
|
34
|
+
|
|
35
|
+
unpack(props),
|
|
36
|
+
}
|
|
37
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
local vide = require("../../vide")
|
|
2
|
+
|
|
3
|
+
local create = vide.create
|
|
4
|
+
|
|
5
|
+
type Can<T> = T | () -> T
|
|
6
|
+
type Container = {
|
|
7
|
+
read size: Can<UDim2>?,
|
|
8
|
+
read position: Can<UDim2>?,
|
|
9
|
+
read anchor: Can<Vector2>?,
|
|
10
|
+
read zindex: Can<number>?,
|
|
11
|
+
read auto: Can<Enum.AutomaticSize | "X" | "Y" | "XY">?,
|
|
12
|
+
read order: Can<number>?,
|
|
13
|
+
read clip: Can<boolean>?,
|
|
14
|
+
|
|
15
|
+
[number]: unknown,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return function(props: Container)
|
|
19
|
+
return create "Frame" {
|
|
20
|
+
Size = props.size,
|
|
21
|
+
Position = props.position,
|
|
22
|
+
AnchorPoint = props.anchor,
|
|
23
|
+
AutomaticSize = props.auto,
|
|
24
|
+
LayoutOrder = props.order,
|
|
25
|
+
ZIndex = props.zindex,
|
|
26
|
+
ClipsDescendants = props.clip,
|
|
27
|
+
|
|
28
|
+
AutoLocalize = false,
|
|
29
|
+
BackgroundTransparency = 1,
|
|
30
|
+
|
|
31
|
+
unpack(props),
|
|
32
|
+
}
|
|
33
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
local fade = require("../fade")
|
|
2
|
+
local state = require("../state")
|
|
3
|
+
local theme = require("../theme")
|
|
4
|
+
local vide = require("../../vide")
|
|
5
|
+
|
|
6
|
+
local create = vide.create
|
|
7
|
+
|
|
8
|
+
type Can<T> = T | () -> T
|
|
9
|
+
type Divider = {
|
|
10
|
+
read order: Can<number>?,
|
|
11
|
+
read visible: Can<boolean>?,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
-- a 1px horizontal rule. It has no width of its own and relies on the parent's
|
|
15
|
+
-- list layout filling it horizontally: a scale width would make an
|
|
16
|
+
-- automatically sized parent grow to fill its own parent
|
|
17
|
+
return function(props: Divider?)
|
|
18
|
+
return create "Frame" {
|
|
19
|
+
Size = UDim2.fromOffset(0, 1),
|
|
20
|
+
BackgroundColor3 = function()
|
|
21
|
+
return theme.border(state.theme())
|
|
22
|
+
end,
|
|
23
|
+
BackgroundTransparency = fade.fade(),
|
|
24
|
+
BorderSizePixel = 0,
|
|
25
|
+
LayoutOrder = props and props.order,
|
|
26
|
+
Visible = props and props.visible,
|
|
27
|
+
}
|
|
28
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
local px = require("../px")
|
|
2
|
+
local vide = require("../../vide")
|
|
3
|
+
|
|
4
|
+
local create = vide.create
|
|
5
|
+
local effect = vide.effect
|
|
6
|
+
local source = vide.source
|
|
7
|
+
local read = vide.read
|
|
8
|
+
|
|
9
|
+
return function()
|
|
10
|
+
local gap = source(UDim.new())
|
|
11
|
+
|
|
12
|
+
local list: UIListLayout = create "UIListLayout" {
|
|
13
|
+
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
14
|
+
Padding = px(gap),
|
|
15
|
+
}
|
|
16
|
+
local t = { list }
|
|
17
|
+
local mt = {}
|
|
18
|
+
|
|
19
|
+
function mt:row()
|
|
20
|
+
list.FillDirection = Enum.FillDirection.Vertical
|
|
21
|
+
return self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
function mt:column()
|
|
25
|
+
list.FillDirection = Enum.FillDirection.Horizontal
|
|
26
|
+
return self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
function mt:name()
|
|
30
|
+
list.SortOrder = Enum.SortOrder.Name
|
|
31
|
+
return self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
function mt:none(direction: "horizontal" | "vertical"?)
|
|
35
|
+
if direction ~= "vertical" then
|
|
36
|
+
list.HorizontalFlex = Enum.UIFlexAlignment.None
|
|
37
|
+
end
|
|
38
|
+
if direction ~= "horizontal" then
|
|
39
|
+
list.VerticalFlex = Enum.UIFlexAlignment.None
|
|
40
|
+
end
|
|
41
|
+
return self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
function mt:even(direction: "horizontal" | "vertical"?)
|
|
45
|
+
if direction ~= "vertical" then
|
|
46
|
+
list.HorizontalFlex = Enum.UIFlexAlignment.SpaceEvenly
|
|
47
|
+
end
|
|
48
|
+
if direction ~= "horizontal" then
|
|
49
|
+
list.VerticalFlex = Enum.UIFlexAlignment.SpaceEvenly
|
|
50
|
+
end
|
|
51
|
+
return self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
function mt:around(direction: "horizontal" | "vertical"?)
|
|
55
|
+
if direction ~= "vertical" then
|
|
56
|
+
list.HorizontalFlex = Enum.UIFlexAlignment.SpaceAround
|
|
57
|
+
end
|
|
58
|
+
if direction ~= "horizontal" then
|
|
59
|
+
list.VerticalFlex = Enum.UIFlexAlignment.SpaceAround
|
|
60
|
+
end
|
|
61
|
+
return self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
function mt:between(direction: "horizontal" | "vertical"?)
|
|
65
|
+
if direction ~= "vertical" then
|
|
66
|
+
list.HorizontalFlex = Enum.UIFlexAlignment.SpaceBetween
|
|
67
|
+
end
|
|
68
|
+
if direction ~= "horizontal" then
|
|
69
|
+
list.VerticalFlex = Enum.UIFlexAlignment.SpaceBetween
|
|
70
|
+
end
|
|
71
|
+
return self
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
function mt:fill(direction: "horizontal" | "vertical")
|
|
75
|
+
if direction ~= "vertical" then
|
|
76
|
+
list.HorizontalFlex = Enum.UIFlexAlignment.Fill
|
|
77
|
+
end
|
|
78
|
+
if direction ~= "horizontal" then
|
|
79
|
+
list.VerticalFlex = Enum.UIFlexAlignment.Fill
|
|
80
|
+
end
|
|
81
|
+
return self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
function mt:horizontal(align: "left" | "right" | "center")
|
|
85
|
+
list.HorizontalAlignment = if align == "left"
|
|
86
|
+
then Enum.HorizontalAlignment.Left
|
|
87
|
+
elseif align == "right" then Enum.HorizontalAlignment.Right
|
|
88
|
+
else Enum.HorizontalAlignment.Center
|
|
89
|
+
return self
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
function mt:vertical(align: "top" | "bottom" | "center")
|
|
93
|
+
list.VerticalAlignment = if align == "top"
|
|
94
|
+
then Enum.VerticalAlignment.Top
|
|
95
|
+
elseif align == "bottom" then Enum.VerticalAlignment.Bottom
|
|
96
|
+
else Enum.VerticalAlignment.Center
|
|
97
|
+
return self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
function mt:gap(value: number | () -> number)
|
|
101
|
+
effect(function()
|
|
102
|
+
gap(UDim.new(0, read(value)))
|
|
103
|
+
end)
|
|
104
|
+
return self
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
return setmetatable(t, { __index = mt })
|
|
108
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
local vide = require("../../vide")
|
|
2
|
+
|
|
3
|
+
local create = vide.create
|
|
4
|
+
local read = vide.read
|
|
5
|
+
|
|
6
|
+
type Can<T> = T | () -> T
|
|
7
|
+
type Gap = {
|
|
8
|
+
read width: Can<number>?,
|
|
9
|
+
read height: Can<number>?,
|
|
10
|
+
|
|
11
|
+
[number]: unknown,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return function(props: Gap)
|
|
15
|
+
return create "Frame" {
|
|
16
|
+
Name = "gap",
|
|
17
|
+
Size = function()
|
|
18
|
+
return UDim2.fromOffset(read(props.width) or 0, read(props.height) or 0)
|
|
19
|
+
end,
|
|
20
|
+
|
|
21
|
+
BackgroundTransparency = 1,
|
|
22
|
+
|
|
23
|
+
unpack(props) :: any,
|
|
24
|
+
}
|
|
25
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
local fade = require("../fade")
|
|
2
|
+
local vide = require("../../vide")
|
|
3
|
+
|
|
4
|
+
local create = vide.create
|
|
5
|
+
|
|
6
|
+
type Can<T> = T | () -> T
|
|
7
|
+
type Image = {
|
|
8
|
+
read image: Can<string>,
|
|
9
|
+
read size: Can<UDim2>?,
|
|
10
|
+
read color: Can<Color3>?,
|
|
11
|
+
read transparency: Can<number>?,
|
|
12
|
+
read order: Can<number>?,
|
|
13
|
+
read visible: Can<boolean>?,
|
|
14
|
+
|
|
15
|
+
[number]: unknown,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return function(props: Image)
|
|
19
|
+
return create "ImageLabel" {
|
|
20
|
+
Image = props.image,
|
|
21
|
+
Size = props.size,
|
|
22
|
+
ImageColor3 = props.color,
|
|
23
|
+
ImageTransparency = fade.fade(props.transparency),
|
|
24
|
+
LayoutOrder = props.order,
|
|
25
|
+
Visible = props.visible,
|
|
26
|
+
ScaleType = Enum.ScaleType.Fit,
|
|
27
|
+
|
|
28
|
+
AutoLocalize = false,
|
|
29
|
+
BackgroundTransparency = 1,
|
|
30
|
+
|
|
31
|
+
unpack(props),
|
|
32
|
+
}
|
|
33
|
+
end
|