@rbxts/centurion-ui 1.0.0-dev-284510d

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.
Files changed (113) hide show
  1. package/out/app/app.d.ts +6 -0
  2. package/out/app/app.lua +83 -0
  3. package/out/app/index.d.ts +1 -0
  4. package/out/app/init.lua +7 -0
  5. package/out/app/terminal-app.d.ts +1 -0
  6. package/out/app/terminal-app.lua +61 -0
  7. package/out/components/history/history-line.d.ts +10 -0
  8. package/out/components/history/history-line.lua +63 -0
  9. package/out/components/history/history-list.d.ts +15 -0
  10. package/out/components/history/history-list.lua +62 -0
  11. package/out/components/history/index.d.ts +1 -0
  12. package/out/components/history/init.lua +7 -0
  13. package/out/components/index.d.ts +1 -0
  14. package/out/components/init.lua +7 -0
  15. package/out/components/suggestions/badge.d.ts +16 -0
  16. package/out/components/suggestions/badge.lua +52 -0
  17. package/out/components/suggestions/index.d.ts +1 -0
  18. package/out/components/suggestions/init.lua +7 -0
  19. package/out/components/suggestions/main-suggestion.d.ts +12 -0
  20. package/out/components/suggestions/main-suggestion.lua +180 -0
  21. package/out/components/suggestions/suggestion-list.d.ts +8 -0
  22. package/out/components/suggestions/suggestion-list.lua +70 -0
  23. package/out/components/suggestions/suggestions.d.ts +1 -0
  24. package/out/components/suggestions/suggestions.lua +117 -0
  25. package/out/components/suggestions/types.d.ts +6 -0
  26. package/out/components/suggestions/types.lua +2 -0
  27. package/out/components/suggestions/util.d.ts +4 -0
  28. package/out/components/suggestions/util.lua +72 -0
  29. package/out/components/terminal-text-field.d.ts +11 -0
  30. package/out/components/terminal-text-field.lua +289 -0
  31. package/out/components/terminal-window.d.ts +1 -0
  32. package/out/components/terminal-window.lua +265 -0
  33. package/out/components/terminal.d.ts +1 -0
  34. package/out/components/terminal.lua +26 -0
  35. package/out/components/ui/frame.d.ts +20 -0
  36. package/out/components/ui/frame.lua +29 -0
  37. package/out/components/ui/group.d.ts +17 -0
  38. package/out/components/ui/group.lua +24 -0
  39. package/out/components/ui/layer.d.ts +7 -0
  40. package/out/components/ui/layer.lua +23 -0
  41. package/out/components/ui/outline.d.ts +14 -0
  42. package/out/components/ui/outline.lua +106 -0
  43. package/out/components/ui/padding.d.ts +10 -0
  44. package/out/components/ui/padding.lua +19 -0
  45. package/out/components/ui/scrolling-frame.d.ts +15 -0
  46. package/out/components/ui/scrolling-frame.lua +42 -0
  47. package/out/components/ui/shortcut-group.d.ts +6 -0
  48. package/out/components/ui/shortcut-group.lua +100 -0
  49. package/out/components/ui/text-field.d.ts +13 -0
  50. package/out/components/ui/text-field.lua +53 -0
  51. package/out/components/ui/text.d.ts +20 -0
  52. package/out/components/ui/text.lua +55 -0
  53. package/out/constants/options.d.ts +2 -0
  54. package/out/constants/options.lua +19 -0
  55. package/out/constants/springs.d.ts +19 -0
  56. package/out/constants/springs.lua +20 -0
  57. package/out/constants/text.d.ts +3 -0
  58. package/out/constants/text.lua +9 -0
  59. package/out/constants/util.d.ts +1 -0
  60. package/out/constants/util.lua +7 -0
  61. package/out/hooks/use-motion.d.ts +4 -0
  62. package/out/hooks/use-motion.lua +24 -0
  63. package/out/hooks/use-px.d.ts +24 -0
  64. package/out/hooks/use-px.lua +56 -0
  65. package/out/hooks/use-store.d.ts +3 -0
  66. package/out/hooks/use-store.lua +7 -0
  67. package/out/index.d.ts +2 -0
  68. package/out/init.lua +10 -0
  69. package/out/palette.d.ts +56 -0
  70. package/out/palette.lua +51 -0
  71. package/out/providers/api-provider.d.ts +8 -0
  72. package/out/providers/api-provider.lua +17 -0
  73. package/out/providers/options-provider.d.ts +13 -0
  74. package/out/providers/options-provider.lua +39 -0
  75. package/out/providers/root-provider.d.ts +11 -0
  76. package/out/providers/root-provider.lua +24 -0
  77. package/out/store/app/app-selectors.d.ts +2 -0
  78. package/out/store/app/app-selectors.lua +7 -0
  79. package/out/store/app/app-slice.d.ts +8 -0
  80. package/out/store/app/app-slice.lua +17 -0
  81. package/out/store/app/index.d.ts +2 -0
  82. package/out/store/app/init.lua +10 -0
  83. package/out/store/command/command-selectors.d.ts +2 -0
  84. package/out/store/command/command-selectors.lua +7 -0
  85. package/out/store/command/command-slice.d.ts +15 -0
  86. package/out/store/command/command-slice.lua +21 -0
  87. package/out/store/command/index.d.ts +2 -0
  88. package/out/store/command/init.lua +10 -0
  89. package/out/store/history/history-slice.d.ts +11 -0
  90. package/out/store/history/history-slice.lua +52 -0
  91. package/out/store/history/index.d.ts +1 -0
  92. package/out/store/history/init.lua +7 -0
  93. package/out/store/index.d.ts +46 -0
  94. package/out/store/init.lua +18 -0
  95. package/out/store/suggestion/index.d.ts +2 -0
  96. package/out/store/suggestion/init.lua +10 -0
  97. package/out/store/suggestion/suggestion-selectors.d.ts +2 -0
  98. package/out/store/suggestion/suggestion-selectors.lua +7 -0
  99. package/out/store/suggestion/suggestion-slice.d.ts +9 -0
  100. package/out/store/suggestion/suggestion-slice.lua +15 -0
  101. package/out/store/text/index.d.ts +2 -0
  102. package/out/store/text/init.lua +10 -0
  103. package/out/store/text/text-selectors.d.ts +3 -0
  104. package/out/store/text/text-selectors.lua +11 -0
  105. package/out/store/text/text-slice.d.ts +20 -0
  106. package/out/store/text/text-slice.lua +29 -0
  107. package/out/types.d.ts +40 -0
  108. package/out/types.lua +2 -0
  109. package/out/util/argument.d.ts +2 -0
  110. package/out/util/argument.lua +26 -0
  111. package/out/util/suggestion.d.ts +4 -0
  112. package/out/util/suggestion.lua +208 -0
  113. package/package.json +54 -0
@@ -0,0 +1,70 @@
1
+ -- Compiled with roblox-ts v2.3.0-dev-26ec859
2
+ local TS = _G[script]
3
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
+ local React = _react
5
+ local useContext = _react.useContext
6
+ local SUGGESTION_TEXT_SIZE = TS.import(script, script.Parent.Parent.Parent, "constants", "text").SUGGESTION_TEXT_SIZE
7
+ local usePx = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-px").usePx
8
+ local OptionsContext = TS.import(script, script.Parent.Parent.Parent, "providers", "options-provider").OptionsContext
9
+ local Frame = TS.import(script, script.Parent.Parent, "ui", "frame").Frame
10
+ local Group = TS.import(script, script.Parent.Parent, "ui", "group").Group
11
+ local Padding = TS.import(script, script.Parent.Parent, "ui", "padding").Padding
12
+ local Text = TS.import(script, script.Parent.Parent, "ui", "text").Text
13
+ local highlightMatching = TS.import(script, script.Parent, "util").highlightMatching
14
+ local function SuggestionList(_param)
15
+ local suggestion = _param.suggestion
16
+ local currentText = _param.currentText
17
+ local size = _param.size
18
+ local px = usePx()
19
+ local options = useContext(OptionsContext)
20
+ local _exp = React.createElement("uilistlayout", {
21
+ SortOrder = "LayoutOrder",
22
+ Padding = UDim.new(0, px(8)),
23
+ })
24
+ local _result = suggestion
25
+ if _result ~= nil then
26
+ _result = _result.others
27
+ if _result ~= nil then
28
+ -- ▼ ReadonlyArray.map ▼
29
+ local _newValue = table.create(#_result)
30
+ local _callback = function(name, i)
31
+ return React.createElement(Frame, {
32
+ key = `{i}-{name}`,
33
+ size = UDim2.new(1, 0, 0, px(SUGGESTION_TEXT_SIZE + 6)),
34
+ backgroundColor = options.palette.background,
35
+ backgroundTransparency = options.backgroundTransparency,
36
+ cornerRadius = UDim.new(0, px(8)),
37
+ clipsDescendants = true,
38
+ }, React.createElement(Padding, {
39
+ all = UDim.new(0, px(4)),
40
+ }), React.createElement(Text, {
41
+ size = UDim2.new(1, 0, 1, 0),
42
+ text = highlightMatching(options.palette.highlight, name, currentText),
43
+ textColor = options.palette.text,
44
+ textSize = px(SUGGESTION_TEXT_SIZE),
45
+ textXAlignment = "Left",
46
+ richText = true,
47
+ }))
48
+ end
49
+ for _k, _v in _result do
50
+ _newValue[_k] = _callback(_v, _k - 1, _result)
51
+ end
52
+ -- ▲ ReadonlyArray.map ▲
53
+ _result = _newValue
54
+ end
55
+ end
56
+ return React.createElement(Group, {
57
+ size = size,
58
+ event = {
59
+ MouseEnter = function()
60
+ return options.setMouseOnGUI(true)
61
+ end,
62
+ MouseLeave = function()
63
+ return options.setMouseOnGUI(false)
64
+ end,
65
+ },
66
+ }, _exp, _result)
67
+ end
68
+ return {
69
+ SuggestionList = SuggestionList,
70
+ }
@@ -0,0 +1 @@
1
+ export declare function Suggestions(): JSX.Element;
@@ -0,0 +1,117 @@
1
+ -- Compiled with roblox-ts v2.3.0-dev-26ec859
2
+ local TS = _G[script]
3
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
+ local React = _react
5
+ local useBinding = _react.useBinding
6
+ local useContext = _react.useContext
7
+ local useEffect = _react.useEffect
8
+ local useMemo = _react.useMemo
9
+ local useSelector = TS.import(script, TS.getModule(script, "@rbxts", "react-reflex")).useSelector
10
+ local TextService = TS.import(script, TS.getModule(script, "@rbxts", "services")).TextService
11
+ local springs = TS.import(script, script.Parent.Parent.Parent, "constants", "springs").springs
12
+ local _text = TS.import(script, script.Parent.Parent.Parent, "constants", "text")
13
+ local SUGGESTION_TEXT_SIZE = _text.SUGGESTION_TEXT_SIZE
14
+ local SUGGESTION_TITLE_TEXT_SIZE = _text.SUGGESTION_TITLE_TEXT_SIZE
15
+ local useMotion = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-motion").useMotion
16
+ local usePx = TS.import(script, script.Parent.Parent.Parent, "hooks", "use-px").usePx
17
+ local OptionsContext = TS.import(script, script.Parent.Parent.Parent, "providers", "options-provider").OptionsContext
18
+ local selectSuggestion = TS.import(script, script.Parent.Parent.Parent, "store", "suggestion").selectSuggestion
19
+ local selectText = TS.import(script, script.Parent.Parent.Parent, "store", "text").selectText
20
+ local Group = TS.import(script, script.Parent.Parent, "ui", "group").Group
21
+ local MainSuggestion = TS.import(script, script.Parent, "main-suggestion").MainSuggestion
22
+ local SuggestionList = TS.import(script, script.Parent, "suggestion-list").SuggestionList
23
+ local getSuggestionTextBounds = TS.import(script, script.Parent, "util").getSuggestionTextBounds
24
+ local MAX_SUGGESTION_WIDTH = 180
25
+ local MAX_BADGE_WIDTH = 80
26
+ local PADDING = 8
27
+ local function Suggestions()
28
+ local options = useContext(OptionsContext)
29
+ local px = usePx()
30
+ local terminalText = useSelector(selectText)
31
+ local currentTextPart = useMemo(function()
32
+ if terminalText.index == -1 or terminalText.index >= #terminalText.parts then
33
+ return nil
34
+ end
35
+ return terminalText.parts[terminalText.index + 1]
36
+ end, { terminalText })
37
+ local textBoundsParams = useMemo(function()
38
+ return Instance.new("GetTextBoundsParams")
39
+ end, {})
40
+ -- Suggestions
41
+ local currentSuggestion = useSelector(selectSuggestion)
42
+ local sizes, setSizes = useBinding({
43
+ title = UDim2.fromOffset(0, px(SUGGESTION_TITLE_TEXT_SIZE)),
44
+ description = UDim2.fromOffset(0, px(SUGGESTION_TEXT_SIZE)),
45
+ errorTextHeight = 0,
46
+ typeBadgeWidth = 0,
47
+ })
48
+ local suggestionSize, suggestionSizeMotion = useMotion(UDim2.new())
49
+ local otherSuggestionSize, otherSuggestionSizeMotion = useMotion(UDim2.new())
50
+ -- Resize window based on suggestions
51
+ useEffect(function()
52
+ if currentSuggestion == nil then
53
+ suggestionSizeMotion:spring(UDim2.new())
54
+ otherSuggestionSizeMotion:spring(UDim2.new())
55
+ return nil
56
+ end
57
+ local mainSuggestion = currentSuggestion.main
58
+ local otherSuggestions = currentSuggestion.others
59
+ if #otherSuggestions == 0 then
60
+ otherSuggestionSizeMotion:spring(UDim2.new())
61
+ end
62
+ local textBounds = getSuggestionTextBounds(options, mainSuggestion, px(SUGGESTION_TITLE_TEXT_SIZE), px(SUGGESTION_TEXT_SIZE), px(MAX_SUGGESTION_WIDTH), px(MAX_BADGE_WIDTH))
63
+ setSizes(textBounds)
64
+ local windowWidth = math.max(textBounds.title.X.Offset, textBounds.description.X.Offset) + px(PADDING * 2)
65
+ local windowHeight = textBounds.title.Y.Offset + textBounds.description.Y.Offset + textBounds.errorTextHeight + px(PADDING * 2)
66
+ if textBounds.typeBadgeWidth > 0 then
67
+ windowWidth += textBounds.typeBadgeWidth + px(16)
68
+ end
69
+ if textBounds.errorTextHeight > 0 then
70
+ windowHeight += px(8)
71
+ end
72
+ -- Calculate other suggestion sizes
73
+ local otherHeight = 0
74
+ if not (#otherSuggestions == 0) then
75
+ local maxSuggestionWidth = 0
76
+ textBoundsParams.Font = options.font.regular
77
+ textBoundsParams.Size = px(SUGGESTION_TEXT_SIZE)
78
+ textBoundsParams.Width = math.huge
79
+ for _, name in otherSuggestions do
80
+ textBoundsParams.Text = name
81
+ local suggestionBounds = TextService:GetTextBoundsAsync(textBoundsParams)
82
+ if suggestionBounds.X > maxSuggestionWidth then
83
+ maxSuggestionWidth = suggestionBounds.X
84
+ end
85
+ end
86
+ otherHeight = #otherSuggestions * px(SUGGESTION_TEXT_SIZE + 6) + (#otherSuggestions - 1) * px(4) + px(8)
87
+ windowWidth = math.max(windowWidth, maxSuggestionWidth)
88
+ otherSuggestionSizeMotion:spring(UDim2.fromOffset(windowWidth, otherHeight), springs.gentle)
89
+ end
90
+ suggestionSizeMotion:spring(UDim2.fromOffset(windowWidth, windowHeight), springs.responsive)
91
+ end, { currentSuggestion, px })
92
+ local _attributes = {
93
+ suggestion = currentSuggestion,
94
+ }
95
+ local _result = currentSuggestion
96
+ if _result ~= nil then
97
+ _result = _result.main.type
98
+ end
99
+ _attributes.argument = _result == "argument"
100
+ _attributes.currentText = currentTextPart
101
+ _attributes.size = suggestionSize
102
+ _attributes.sizes = sizes
103
+ return React.createElement(Group, {
104
+ size = UDim2.fromScale(1, 1),
105
+ visible = currentSuggestion ~= nil,
106
+ }, React.createElement(MainSuggestion, _attributes), React.createElement(SuggestionList, {
107
+ suggestion = currentSuggestion,
108
+ currentText = currentTextPart,
109
+ size = otherSuggestionSize,
110
+ }), React.createElement("uilistlayout", {
111
+ SortOrder = "LayoutOrder",
112
+ Padding = UDim.new(0, px(PADDING)),
113
+ }))
114
+ end
115
+ return {
116
+ Suggestions = Suggestions,
117
+ }
@@ -0,0 +1,6 @@
1
+ export interface SuggestionTextBounds {
2
+ title: UDim2;
3
+ description: UDim2;
4
+ errorTextHeight: number;
5
+ typeBadgeWidth: number;
6
+ }
@@ -0,0 +1,2 @@
1
+ -- Compiled with roblox-ts v2.3.0-dev-26ec859
2
+ return nil
@@ -0,0 +1,4 @@
1
+ import { ArgumentSuggestion, CommandSuggestion, InterfaceOptions } from "../../types";
2
+ import { SuggestionTextBounds } from "./types";
3
+ export declare function highlightMatching(color: Color3, text?: string, terminalText?: string): string;
4
+ export declare function getSuggestionTextBounds(options: InterfaceOptions, suggestion: ArgumentSuggestion | CommandSuggestion, titleTextSize: number, textSize: number, maxWidth: number, maxBadgeWidth: number): SuggestionTextBounds;
@@ -0,0 +1,72 @@
1
+ -- Compiled with roblox-ts v2.3.0-dev-26ec859
2
+ local TS = _G[script]
3
+ local TextService = TS.import(script, TS.getModule(script, "@rbxts", "services")).TextService
4
+ local TEXT_BOUNDS_PARAMS = Instance.new("GetTextBoundsParams")
5
+ local DEFAULT_BOUNDS = Vector2.new()
6
+ local prevColor
7
+ local prevColorHex
8
+ local function highlightMatching(color, text, terminalText)
9
+ if text == nil then
10
+ return ""
11
+ end
12
+ if terminalText == nil then
13
+ return text
14
+ end
15
+ local _text = text
16
+ local _arg1 = #terminalText
17
+ local subText = string.sub(_text, 0, _arg1)
18
+ if string.lower(terminalText) ~= string.lower(subText) then
19
+ return text
20
+ end
21
+ if prevColor ~= color then
22
+ prevColor = color
23
+ prevColorHex = color:ToHex()
24
+ end
25
+ local _text_1 = text
26
+ local _arg0 = #terminalText + 1
27
+ local unhighlightedText = string.sub(_text_1, _arg0)
28
+ return `<font color="#{prevColorHex}">{subText}</font>{unhighlightedText}`
29
+ end
30
+ local function getSuggestionTextBounds(options, suggestion, titleTextSize, textSize, maxWidth, maxBadgeWidth)
31
+ -- Get title text bounds
32
+ TEXT_BOUNDS_PARAMS.Text = suggestion.title
33
+ TEXT_BOUNDS_PARAMS.Size = titleTextSize
34
+ TEXT_BOUNDS_PARAMS.Font = options.font.bold
35
+ local titleBounds = TextService:GetTextBoundsAsync(TEXT_BOUNDS_PARAMS)
36
+ -- Get description text bounds
37
+ TEXT_BOUNDS_PARAMS.Width = maxWidth
38
+ TEXT_BOUNDS_PARAMS.Size = textSize
39
+ TEXT_BOUNDS_PARAMS.Font = options.font.regular
40
+ local descriptionBounds = DEFAULT_BOUNDS
41
+ if suggestion.description ~= nil then
42
+ TEXT_BOUNDS_PARAMS.Text = suggestion.description
43
+ descriptionBounds = TextService:GetTextBoundsAsync(TEXT_BOUNDS_PARAMS)
44
+ end
45
+ local errorTextHeight = 0
46
+ local typeBadgeWidth = 0
47
+ if suggestion.type == "argument" then
48
+ -- Get error text bounds
49
+ if suggestion.error ~= nil then
50
+ local _condition = suggestion.error
51
+ if _condition == nil then
52
+ _condition = ""
53
+ end
54
+ TEXT_BOUNDS_PARAMS.Text = _condition
55
+ errorTextHeight = TextService:GetTextBoundsAsync(TEXT_BOUNDS_PARAMS).Y
56
+ end
57
+ -- Get type badge bounds
58
+ TEXT_BOUNDS_PARAMS.Text = suggestion.dataType
59
+ TEXT_BOUNDS_PARAMS.Width = maxBadgeWidth
60
+ typeBadgeWidth = TextService:GetTextBoundsAsync(TEXT_BOUNDS_PARAMS).X
61
+ end
62
+ return {
63
+ title = UDim2.fromOffset(titleBounds.X, titleBounds.Y),
64
+ description = UDim2.fromOffset(descriptionBounds.X, descriptionBounds.Y),
65
+ errorTextHeight = errorTextHeight,
66
+ typeBadgeWidth = typeBadgeWidth,
67
+ }
68
+ end
69
+ return {
70
+ highlightMatching = highlightMatching,
71
+ getSuggestionTextBounds = getSuggestionTextBounds,
72
+ }
@@ -0,0 +1,11 @@
1
+ import { BindingOrValue } from "@rbxts/pretty-react-hooks";
2
+ interface TerminalTextFieldProps {
3
+ anchorPoint?: BindingOrValue<Vector2>;
4
+ size?: BindingOrValue<UDim2>;
5
+ position?: BindingOrValue<UDim2>;
6
+ backgroundTransparency?: BindingOrValue<number>;
7
+ onTextChange?: (text: string) => void;
8
+ onSubmit?: (text: string) => void;
9
+ }
10
+ export declare function TerminalTextField({ anchorPoint, size, position, backgroundTransparency, onTextChange, onSubmit, }: TerminalTextFieldProps): JSX.Element;
11
+ export {};
@@ -0,0 +1,289 @@
1
+ -- Compiled with roblox-ts v2.3.0-dev-26ec859
2
+ local TS = _G[script]
3
+ local _string = TS.import(script, TS.getModule(script, "@rbxts", "centurion").out.shared.util.string)
4
+ local endsWithSpace = _string.endsWithSpace
5
+ local formatPartsAsPath = _string.formatPartsAsPath
6
+ local _pretty_react_hooks = TS.import(script, TS.getModule(script, "@rbxts", "pretty-react-hooks").out)
7
+ local getBindingValue = _pretty_react_hooks.getBindingValue
8
+ local useEventListener = _pretty_react_hooks.useEventListener
9
+ local useMountEffect = _pretty_react_hooks.useMountEffect
10
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
11
+ local React = _react
12
+ local useBinding = _react.useBinding
13
+ local useCallback = _react.useCallback
14
+ local useContext = _react.useContext
15
+ local useEffect = _react.useEffect
16
+ local useRef = _react.useRef
17
+ local useState = _react.useState
18
+ local useSelector = TS.import(script, TS.getModule(script, "@rbxts", "react-reflex")).useSelector
19
+ local UserInputService = TS.import(script, TS.getModule(script, "@rbxts", "services")).UserInputService
20
+ local usePx = TS.import(script, script.Parent.Parent, "hooks", "use-px").usePx
21
+ local useStore = TS.import(script, script.Parent.Parent, "hooks", "use-store").useStore
22
+ local ApiContext = TS.import(script, script.Parent.Parent, "providers", "api-provider").ApiContext
23
+ local OptionsContext = TS.import(script, script.Parent.Parent, "providers", "options-provider").OptionsContext
24
+ local selectVisible = TS.import(script, script.Parent.Parent, "store", "app").selectVisible
25
+ local selectCommand = TS.import(script, script.Parent.Parent, "store", "command").selectCommand
26
+ local selectSuggestion = TS.import(script, script.Parent.Parent, "store", "suggestion").selectSuggestion
27
+ local selectValid = TS.import(script, script.Parent.Parent, "store", "text").selectValid
28
+ local getArgumentNames = TS.import(script, script.Parent.Parent, "util", "argument").getArgumentNames
29
+ local Frame = TS.import(script, script.Parent, "ui", "frame").Frame
30
+ local Padding = TS.import(script, script.Parent, "ui", "padding").Padding
31
+ local Text = TS.import(script, script.Parent, "ui", "text").Text
32
+ local TextField = TS.import(script, script.Parent, "ui", "text-field").TextField
33
+ local TEXT_SIZE = 22
34
+ local function TerminalTextField(_param)
35
+ local anchorPoint = _param.anchorPoint
36
+ local size = _param.size
37
+ local position = _param.position
38
+ local backgroundTransparency = _param.backgroundTransparency
39
+ local onTextChange = _param.onTextChange
40
+ local onSubmit = _param.onSubmit
41
+ local px = usePx()
42
+ local ref = useRef()
43
+ local api = useContext(ApiContext)
44
+ local options = useContext(OptionsContext)
45
+ local store = useStore()
46
+ local appVisible = useSelector(selectVisible)
47
+ local currentSuggestion = useSelector(selectSuggestion)
48
+ local text, setText = useBinding("")
49
+ local suggestionText, setSuggestionText = useBinding("")
50
+ local valid, setValid = useState(false)
51
+ local traverseHistory = useCallback(function(up)
52
+ local history = store:getState().history.commandHistory
53
+ if #history == 0 then
54
+ return nil
55
+ end
56
+ local historyIndex = store:getState().history.commandHistoryIndex
57
+ if (up and historyIndex == 0) or (not up and historyIndex == -1) then
58
+ return nil
59
+ end
60
+ local newIndex
61
+ if up then
62
+ newIndex = if historyIndex == -1 then #history - 1 else historyIndex - 1
63
+ else
64
+ newIndex = if historyIndex ~= #history - 1 then historyIndex + 1 else -1
65
+ end
66
+ local newText = if newIndex ~= -1 then history[newIndex + 1] else ""
67
+ setText(newText)
68
+ setSuggestionText("")
69
+ store.setCommandHistoryIndex(newIndex)
70
+ if ref.current ~= nil then
71
+ ref.current.CursorPosition = #newText + 1
72
+ end
73
+ end, {})
74
+ useEffect(function()
75
+ if ref.current == nil then
76
+ return nil
77
+ end
78
+ if appVisible then
79
+ ref.current:CaptureFocus()
80
+ else
81
+ ref.current:ReleaseFocus()
82
+ end
83
+ end, { appVisible })
84
+ useMountEffect(function()
85
+ store:subscribe(selectValid, function(valid)
86
+ setValid(valid)
87
+ end)
88
+ store:subscribe(selectCommand, function(command)
89
+ if not store:getState().text.valid then
90
+ return nil
91
+ end
92
+ setValid(command ~= nil)
93
+ end)
94
+ end)
95
+ useEffect(function()
96
+ if currentSuggestion == nil then
97
+ setSuggestionText("")
98
+ return nil
99
+ end
100
+ local state = store:getState()
101
+ local atNextPart = endsWithSpace(state.text.value)
102
+ local suggestionStartIndex = if #state.text.parts > 0 then (if not atNextPart then #state.text.parts[#state.text.parts] else 0) + 1 else -1
103
+ local command = state.command.path
104
+ local argIndex = state.command.argIndex
105
+ if currentSuggestion.main.type == "command" and suggestionStartIndex > -1 then
106
+ setSuggestionText(getBindingValue(text) .. string.sub(currentSuggestion.main.title, suggestionStartIndex))
107
+ return nil
108
+ end
109
+ if currentSuggestion.main.type ~= "argument" or command == nil or argIndex == nil then
110
+ return nil
111
+ end
112
+ local newText = getBindingValue(text)
113
+ local argNames = getArgumentNames(api.registry, command)
114
+ for i = argIndex, #argNames - 1 do
115
+ if i == argIndex and not atNextPart then
116
+ if not (#currentSuggestion.others == 0) then
117
+ newText ..= string.sub(currentSuggestion.others[1], suggestionStartIndex)
118
+ end
119
+ newText ..= " "
120
+ continue
121
+ end
122
+ newText = `{newText}{argNames[i + 1]} `
123
+ end
124
+ setSuggestionText(newText)
125
+ end, { currentSuggestion })
126
+ useEventListener(UserInputService.InputBegan, function(input)
127
+ if ref.current == nil or not ref.current:IsFocused() then
128
+ return nil
129
+ end
130
+ if input.KeyCode == Enum.KeyCode.Up then
131
+ traverseHistory(true)
132
+ elseif input.KeyCode == Enum.KeyCode.Down then
133
+ traverseHistory(false)
134
+ end
135
+ if input.KeyCode ~= Enum.KeyCode.Tab then
136
+ return nil
137
+ end
138
+ local state = store:getState()
139
+ local commandPath = state.command.path
140
+ -- Handle command suggestions
141
+ if commandPath == nil then
142
+ local _suggestionTitle = currentSuggestion
143
+ if _suggestionTitle ~= nil then
144
+ _suggestionTitle = _suggestionTitle.main.title
145
+ end
146
+ local suggestionTitle = _suggestionTitle
147
+ if suggestionTitle == nil then
148
+ return nil
149
+ end
150
+ local currentText = text:getValue()
151
+ local newText = ""
152
+ if endsWithSpace(currentText) then
153
+ newText = currentText .. suggestionTitle
154
+ elseif not (#state.text.parts == 0) then
155
+ local textPartSize = #state.text.parts[#state.text.parts]
156
+ local _arg1 = #currentText - textPartSize
157
+ newText = string.sub(currentText, 0, _arg1) .. suggestionTitle
158
+ end
159
+ local suggestionTextParts = string.split((string.gsub(suggestionText:getValue(), "%s+", " ")), " ")
160
+ local _nextCommand = api.registry:getCommandByString(formatPartsAsPath(suggestionTextParts))
161
+ if _nextCommand ~= nil then
162
+ _nextCommand = _nextCommand.options
163
+ end
164
+ local nextCommand = _nextCommand
165
+ local _condition = nextCommand == nil
166
+ if not _condition then
167
+ local _result = nextCommand.arguments
168
+ if _result ~= nil then
169
+ _result = #_result
170
+ end
171
+ local _condition_1 = _result
172
+ if _condition_1 == nil then
173
+ _condition_1 = 0
174
+ end
175
+ _condition = _condition_1 > 0
176
+ end
177
+ if _condition then
178
+ newText ..= " "
179
+ end
180
+ setSuggestionText("")
181
+ setText(newText)
182
+ ref.current.CursorPosition = #newText + 1
183
+ return nil
184
+ end
185
+ -- Handle argument suggestions
186
+ if commandPath == nil or currentSuggestion == nil or #currentSuggestion.others == 0 then
187
+ return nil
188
+ end
189
+ local argIndex = state.command.argIndex
190
+ local _commandArgs = api.registry:getCommand(commandPath)
191
+ if _commandArgs ~= nil then
192
+ _commandArgs = _commandArgs.options.arguments
193
+ end
194
+ local commandArgs = _commandArgs
195
+ if argIndex == nil or commandArgs == nil then
196
+ return nil
197
+ end
198
+ local newText = getBindingValue(text)
199
+ local parts = state.text.parts
200
+ if not endsWithSpace(newText) and not (#parts == 0) then
201
+ local _newText = newText
202
+ local _arg1 = #newText - #parts[#parts]
203
+ newText = string.sub(_newText, 0, _arg1)
204
+ end
205
+ local suggestion = currentSuggestion.others[1]
206
+ if (string.match(suggestion, "%s")) ~= nil then
207
+ suggestion = `"{suggestion}"`
208
+ end
209
+ newText ..= suggestion
210
+ if argIndex < #commandArgs - 1 then
211
+ newText ..= " "
212
+ end
213
+ setSuggestionText("")
214
+ setText(newText)
215
+ ref.current.CursorPosition = #newText + 1
216
+ end)
217
+ return React.createElement(Frame, {
218
+ anchorPoint = anchorPoint,
219
+ size = size,
220
+ position = position,
221
+ backgroundColor = options.palette.surface,
222
+ backgroundTransparency = backgroundTransparency,
223
+ cornerRadius = UDim.new(0, px(4)),
224
+ }, React.createElement(Padding, {
225
+ all = UDim.new(0, px(8)),
226
+ }), React.createElement(TextField, {
227
+ size = UDim2.fromScale(1, 1),
228
+ placeholderText = "Enter command...",
229
+ text = text,
230
+ textSize = px(TEXT_SIZE),
231
+ textColor = if valid then options.palette.success else options.palette.error,
232
+ placeholderColor = options.palette.subtext,
233
+ textXAlignment = "Left",
234
+ clearTextOnFocus = false,
235
+ font = options.font.medium,
236
+ ref = ref,
237
+ event = {
238
+ FocusLost = function(rbx, enterPressed)
239
+ if not enterPressed then
240
+ return nil
241
+ end
242
+ store.addCommandHistory(rbx.Text, api.options.historyLength)
243
+ store.setCommandHistoryIndex(-1)
244
+ local _result = onSubmit
245
+ if _result ~= nil then
246
+ _result(rbx.Text)
247
+ end
248
+ local _result_1 = ref.current
249
+ if _result_1 ~= nil then
250
+ _result_1:CaptureFocus()
251
+ end
252
+ setText("")
253
+ end,
254
+ },
255
+ change = {
256
+ Text = function(rbx)
257
+ local newText = rbx.Text
258
+ -- Remove line breaks
259
+ if (string.match(newText, "[\n\r]")) ~= nil then
260
+ newText = (string.gsub(newText, "[\n\r]", ""))
261
+ end
262
+ -- Remove all tabs from text input - we use these for autocompletion
263
+ if (string.match(newText, "\t")) ~= nil then
264
+ newText = (string.gsub(newText, "\t", ""))
265
+ end
266
+ -- Reset command history index
267
+ if store:getState().history.commandHistoryIndex ~= -1 then
268
+ store.setCommandHistoryIndex(-1)
269
+ end
270
+ setText(newText)
271
+ local _result = onTextChange
272
+ if _result ~= nil then
273
+ _result(newText)
274
+ end
275
+ end,
276
+ },
277
+ zIndex = 2,
278
+ }), React.createElement(Text, {
279
+ size = UDim2.fromScale(1, 1),
280
+ text = suggestionText,
281
+ textColor = options.palette.subtext,
282
+ textSize = px(TEXT_SIZE),
283
+ textXAlignment = "Left",
284
+ font = options.font.medium,
285
+ }))
286
+ end
287
+ return {
288
+ TerminalTextField = TerminalTextField,
289
+ }
@@ -0,0 +1 @@
1
+ export declare function TerminalWindow(): JSX.Element;