@rbxts-ui/components 2.0.0 → 2.1.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.
Files changed (56) hide show
  1. package/dist/Accordion.d.ts +16 -0
  2. package/dist/Accordion.luau +105 -0
  3. package/dist/Button.d.ts +15 -0
  4. package/dist/Button.luau +66 -0
  5. package/dist/Checkbox.d.ts +13 -0
  6. package/dist/Checkbox.luau +113 -0
  7. package/dist/CheckboxRow.d.ts +14 -0
  8. package/dist/CheckboxRow.luau +52 -0
  9. package/dist/ClickOutsideOverlay.d.ts +11 -0
  10. package/dist/ClickOutsideOverlay.luau +35 -0
  11. package/dist/Dropdown.d.ts +18 -0
  12. package/dist/Dropdown.luau +160 -0
  13. package/dist/DropdownButton.d.ts +22 -0
  14. package/dist/DropdownButton.luau +111 -0
  15. package/dist/DropdownOptionButton.d.ts +13 -0
  16. package/dist/DropdownOptionButton.luau +70 -0
  17. package/dist/FormRow.d.ts +11 -0
  18. package/dist/FormRow.luau +39 -0
  19. package/dist/IconRoundButton.d.ts +23 -0
  20. package/dist/IconRoundButton.luau +149 -0
  21. package/dist/IconTileButton.d.ts +14 -0
  22. package/dist/IconTileButton.luau +89 -0
  23. package/dist/Legend.d.ts +11 -0
  24. package/dist/Legend.luau +54 -0
  25. package/dist/Outline.d.ts +16 -0
  26. package/dist/Outline.luau +102 -0
  27. package/dist/PillText.d.ts +8 -0
  28. package/dist/PillText.luau +69 -0
  29. package/dist/PrimaryButton.d.ts +25 -0
  30. package/dist/PrimaryButton.luau +89 -0
  31. package/dist/Radio.d.ts +13 -0
  32. package/dist/Radio.luau +110 -0
  33. package/dist/RadioRow.d.ts +10 -0
  34. package/dist/RadioRow.luau +50 -0
  35. package/dist/ReactiveButton.d.ts +34 -0
  36. package/dist/ReactiveButton.luau +168 -0
  37. package/dist/Section.d.ts +12 -0
  38. package/dist/Section.luau +54 -0
  39. package/dist/SegmentedToggle.d.ts +19 -0
  40. package/dist/SegmentedToggle.luau +120 -0
  41. package/dist/TextButton.d.ts +32 -0
  42. package/dist/TextButton.luau +125 -0
  43. package/dist/TimeAgo.d.ts +8 -0
  44. package/dist/TimeAgo.luau +48 -0
  45. package/dist/index.d.ts +26 -0
  46. package/dist/init.luau +37 -0
  47. package/dist/theme.d.ts +41 -0
  48. package/dist/theme.luau +58 -0
  49. package/dist/tsconfig.tsbuildinfo +1 -1
  50. package/dist/use-button-animation.d.ts +38 -0
  51. package/dist/use-button-animation.luau +83 -0
  52. package/dist/use-button-state.d.ts +13 -0
  53. package/dist/use-button-state.luau +81 -0
  54. package/dist/use-input-device.d.ts +7 -0
  55. package/dist/use-input-device.luau +38 -0
  56. package/package.json +13 -3
@@ -0,0 +1,16 @@
1
+ import React from "@rbxts/react";
2
+ import { type Theme } from "./theme";
3
+ interface AccordionProps {
4
+ title: string;
5
+ children: React.ReactNode;
6
+ isExpanded: boolean;
7
+ onExpandedChange: (expanded: boolean) => void;
8
+ backgroundColor?: Color3;
9
+ backgroundTransparency?: number;
10
+ cornerRadius?: number;
11
+ sortOrder?: Enum.SortOrder;
12
+ theme?: Theme;
13
+ }
14
+ export declare function Accordion({ title, children, backgroundColor, backgroundTransparency, cornerRadius, sortOrder, isExpanded, onExpandedChange, theme, }: AccordionProps): JSX.Element;
15
+ export type { AccordionProps };
16
+ //# sourceMappingURL=Accordion.d.ts.map
@@ -0,0 +1,105 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local VStack = TS.import(script, TS.getModule(script, "@rbxts-ui", "layout").dist).VStack
4
+ local Text = TS.import(script, TS.getModule(script, "@rbxts-ui", "primitives").dist).Text
5
+ local useRem = TS.import(script, TS.getModule(script, "@rbxts-ui", "rem").dist).useRem
6
+ local useMotion = TS.import(script, TS.getModule(script, "@rbxts", "pretty-react-hooks").out).useMotion
7
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
8
+ local React = _react
9
+ local useEffect = _react.useEffect
10
+ local useState = _react.useState
11
+ local ReactiveButton = TS.import(script, script.Parent, "ReactiveButton").ReactiveButton
12
+ local defaultTheme = TS.import(script, script.Parent, "theme").defaultTheme
13
+ local DEFAULT_EXPANDED = true
14
+ local function Accordion(_param)
15
+ local title = _param.title
16
+ local children = _param.children
17
+ local backgroundColor = _param.backgroundColor
18
+ local backgroundTransparency = _param.backgroundTransparency
19
+ if backgroundTransparency == nil then
20
+ backgroundTransparency = 0.8
21
+ end
22
+ local cornerRadius = _param.cornerRadius
23
+ if cornerRadius == nil then
24
+ cornerRadius = 2
25
+ end
26
+ local sortOrder = _param.sortOrder
27
+ if sortOrder == nil then
28
+ sortOrder = Enum.SortOrder.Name
29
+ end
30
+ local isExpanded = _param.isExpanded
31
+ local onExpandedChange = _param.onExpandedChange
32
+ local theme = _param.theme
33
+ if theme == nil then
34
+ theme = defaultTheme
35
+ end
36
+ local rem = useRem()
37
+ local contentHeight, setContentHeight = useState(0)
38
+ -- Header visual height must match the header button height below (rem(5))
39
+ local headerHeight = rem(5)
40
+ local size, sizeMotion = useMotion(UDim2.new(1, 0, 0, headerHeight))
41
+ local contentSize, contentSizeMotion = useMotion(UDim2.new(1, 0, 0, if isExpanded then contentHeight else 0))
42
+ local textSize = rem(3.5)
43
+ local defaultBgColor = backgroundColor or theme.palette.blueishColor
44
+ useEffect(function()
45
+ local target = if isExpanded then contentHeight else 0
46
+ contentSizeMotion:spring(UDim2.new(1, 0, 0, target), theme.springs.gentle)
47
+ -- Keep outer size equal to header + animated content height for clipping
48
+ sizeMotion:spring(UDim2.new(1, 0, 0, headerHeight + target), theme.springs.gentle)
49
+ end, { isExpanded, contentHeight, headerHeight })
50
+ local handleToggle = function()
51
+ local nextExpanded = not isExpanded
52
+ onExpandedChange(nextExpanded)
53
+ end
54
+ return React.createElement(VStack, {
55
+ size = size,
56
+ backgroundTransparency = backgroundTransparency,
57
+ backgroundColor = defaultBgColor,
58
+ verticalAlignment = Enum.VerticalAlignment.Center,
59
+ clipsDescendants = true,
60
+ }, React.createElement("uicorner", {
61
+ CornerRadius = UDim.new(0, rem(cornerRadius)),
62
+ }), React.createElement(ReactiveButton, {
63
+ onClick = handleToggle,
64
+ backgroundTransparency = 1,
65
+ size = UDim2.new(1, 0, 0, rem(5)),
66
+ theme = theme,
67
+ }, React.createElement(Text, {
68
+ text = title,
69
+ textSize = textSize,
70
+ font = theme.fonts.roboto.light,
71
+ textScaled = true,
72
+ textColor = theme.palette.crust,
73
+ size = UDim2.new(1, 0, 1, 0),
74
+ textYAlignment = "Center",
75
+ }, React.createElement("uiflexitem", {
76
+ FlexMode = Enum.UIFlexMode.Fill,
77
+ })), React.createElement(Text, {
78
+ text = if isExpanded then "×" else "+",
79
+ textSize = rem(4),
80
+ textScaled = true,
81
+ textColor = theme.palette.crust,
82
+ size = UDim2.new(0, rem(5), 1, 0),
83
+ textYAlignment = "Center",
84
+ position = UDim2.new(1, 0, 0, 0),
85
+ anchorPoint = Vector2.new(1, 0),
86
+ })), React.createElement("frame", {
87
+ Size = contentSize,
88
+ BackgroundTransparency = 1,
89
+ ClipsDescendants = true,
90
+ }, React.createElement(VStack, {
91
+ padding = rem(2),
92
+ spacing = rem(2),
93
+ size = UDim2.new(1, 0, 0, 0),
94
+ automaticSize = Enum.AutomaticSize.Y,
95
+ change = {
96
+ AbsoluteSize = function(rbx)
97
+ setContentHeight(rbx.AbsoluteSize.Y)
98
+ end,
99
+ },
100
+ sortOrder = sortOrder,
101
+ }, children)))
102
+ end
103
+ return {
104
+ Accordion = Accordion,
105
+ }
@@ -0,0 +1,15 @@
1
+ import React from "@rbxts/react";
2
+ import { FrameProps } from "@rbxts-ui/primitives";
3
+ export interface ButtonProps extends FrameProps<TextButton> {
4
+ active?: boolean | React.Binding<boolean>;
5
+ onClick?: () => void;
6
+ onMouseDown?: () => void;
7
+ onMouseUp?: () => void;
8
+ onMouseEnter?: () => void;
9
+ onMouseLeave?: () => void;
10
+ onMouseClick?: () => void;
11
+ automaticSize?: Enum.AutomaticSize;
12
+ selectable?: boolean | React.Binding<boolean>;
13
+ }
14
+ export declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<TextButton>>;
15
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1,66 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
+ local React = _react
5
+ local forwardRef = _react.forwardRef
6
+ local Button = forwardRef(function(props, ref)
7
+ local _binding = props
8
+ local onClick = _binding.onClick
9
+ local onMouseDown = _binding.onMouseDown
10
+ local onMouseEnter = _binding.onMouseEnter
11
+ local onMouseLeave = _binding.onMouseLeave
12
+ local onMouseUp = _binding.onMouseUp
13
+ local onMouseClick = _binding.onMouseClick
14
+ local _object = {
15
+ Activated = onClick and (function()
16
+ return onClick()
17
+ end),
18
+ MouseButton1Down = onMouseDown and (function()
19
+ return onMouseDown()
20
+ end),
21
+ MouseButton1Click = onMouseClick and (function()
22
+ return onMouseClick()
23
+ end),
24
+ MouseButton1Up = onMouseUp and (function()
25
+ return onMouseUp()
26
+ end),
27
+ MouseEnter = onMouseEnter and (function()
28
+ return onMouseEnter()
29
+ end),
30
+ MouseLeave = onMouseLeave and (function()
31
+ return onMouseLeave()
32
+ end),
33
+ }
34
+ local _spread = props.event
35
+ if _spread then
36
+ for _k, _v in _spread do
37
+ _object[_k] = _v
38
+ end
39
+ end
40
+ local event = _object
41
+ return React.createElement("textbutton", {
42
+ ref = ref,
43
+ Active = props.active,
44
+ Text = "",
45
+ AutoButtonColor = false,
46
+ Size = props.size,
47
+ Position = props.position,
48
+ AnchorPoint = props.anchorPoint,
49
+ BackgroundColor3 = props.backgroundColor,
50
+ BackgroundTransparency = props.backgroundTransparency,
51
+ ClipsDescendants = props.clipsDescendants,
52
+ Visible = props.visible,
53
+ ZIndex = props.zIndex,
54
+ LayoutOrder = props.layoutOrder,
55
+ BorderSizePixel = 0,
56
+ Selectable = props.selectable,
57
+ Event = event,
58
+ Change = props.change,
59
+ AutomaticSize = props.automaticSize,
60
+ }, props.children, props.cornerRadius and React.createElement("uicorner", {
61
+ CornerRadius = props.cornerRadius,
62
+ }))
63
+ end)
64
+ return {
65
+ Button = Button,
66
+ }
@@ -0,0 +1,13 @@
1
+ import { type Theme } from "./theme";
2
+ interface CheckboxProps {
3
+ checked: boolean;
4
+ onChecked: (checked: boolean) => void;
5
+ text?: string;
6
+ variant?: "default" | "large" | "small";
7
+ position?: UDim2;
8
+ disabled?: boolean;
9
+ theme?: Theme;
10
+ }
11
+ export declare function Checkbox({ checked, onChecked, text, variant, position, disabled, theme, }: CheckboxProps): JSX.Element;
12
+ export type { CheckboxProps };
13
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -0,0 +1,113 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local _pretty_react_hooks = TS.import(script, TS.getModule(script, "@rbxts", "pretty-react-hooks").out)
4
+ local lerpBinding = _pretty_react_hooks.lerpBinding
5
+ local useMotion = _pretty_react_hooks.useMotion
6
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
7
+ local React = _react
8
+ local useMemo = _react.useMemo
9
+ local useRem = TS.import(script, TS.getModule(script, "@rbxts-ui", "rem").dist).useRem
10
+ local Frame = TS.import(script, TS.getModule(script, "@rbxts-ui", "primitives").dist).Frame
11
+ local Outline = TS.import(script, script.Parent, "Outline").Outline
12
+ local ReactiveButton = TS.import(script, script.Parent, "ReactiveButton").ReactiveButton
13
+ local Text = TS.import(script, TS.getModule(script, "@rbxts-ui", "primitives").dist).Text
14
+ local defaultTheme = TS.import(script, script.Parent, "theme").defaultTheme
15
+ local function Checkbox(_param)
16
+ local checked = _param.checked
17
+ local onChecked = _param.onChecked
18
+ local text = _param.text
19
+ local variant = _param.variant
20
+ if variant == nil then
21
+ variant = "default"
22
+ end
23
+ local position = _param.position
24
+ local disabled = _param.disabled
25
+ if disabled == nil then
26
+ disabled = false
27
+ end
28
+ local theme = _param.theme
29
+ if theme == nil then
30
+ theme = defaultTheme
31
+ end
32
+ local rem = useRem()
33
+ local hover, hoverMotion = useMotion(0)
34
+ local checkboxSize = if variant == "large" then 4 elseif variant == "small" then 1.7 else 3
35
+ local buttonSize = UDim2.new(0, rem(checkboxSize), 0, rem(checkboxSize))
36
+ local textWidth, textWidthMotion = useMotion({
37
+ label = 0,
38
+ value = 0,
39
+ })
40
+ local size = useMemo(function()
41
+ return textWidth:map(function(_param_1)
42
+ local label = _param_1.label
43
+ local value = _param_1.value
44
+ local content = math.max(label, value)
45
+ local width = checkboxSize
46
+ return UDim2.new(0, rem(width) + content, 0, rem(checkboxSize))
47
+ end)
48
+ end, { rem })
49
+ local cornerRadius = UDim.new(0, rem(1))
50
+ local mainColor = if disabled then theme.palette.overlay0 else theme.palette.black
51
+ local textColor = if disabled then theme.palette.overlay0 else theme.palette.black
52
+ return React.createElement(ReactiveButton, {
53
+ backgroundTransparency = 1,
54
+ size = size,
55
+ position = position,
56
+ onClick = function()
57
+ return not disabled and onChecked(not checked)
58
+ end,
59
+ onHover = function(hovered)
60
+ return hoverMotion:spring(if hovered then 1 else 0)
61
+ end,
62
+ theme = theme,
63
+ }, React.createElement("uilistlayout", {
64
+ FillDirection = "Horizontal",
65
+ VerticalAlignment = "Center",
66
+ Padding = UDim.new(0, 8),
67
+ }), React.createElement(Frame, {
68
+ backgroundTransparency = 1,
69
+ size = buttonSize,
70
+ }, React.createElement(Frame, {
71
+ backgroundColor = theme.palette.white,
72
+ cornerRadius = cornerRadius,
73
+ size = UDim2.new(1, 0, 1, 0),
74
+ }, React.createElement("uigradient", {
75
+ Offset = lerpBinding(hover, Vector2.new(), Vector2.new(0, 1)),
76
+ Rotation = 90,
77
+ Transparency = NumberSequence.new(0, 0.1),
78
+ })), React.createElement(Outline, {
79
+ outerColor = mainColor,
80
+ innerColor = mainColor,
81
+ cornerRadius = cornerRadius,
82
+ innerTransparency = 0,
83
+ outerTransparency = 1,
84
+ innerThickness = 2,
85
+ theme = theme,
86
+ }), React.createElement(Text, {
87
+ text = if checked then "✔" else "",
88
+ textColor = mainColor,
89
+ textScaled = true,
90
+ size = UDim2.new(1, 0, 1, 0),
91
+ position = UDim2.new(0.5, 0, 0.5, 0),
92
+ anchorPoint = Vector2.new(0.5, 0.5),
93
+ textXAlignment = "Center",
94
+ textYAlignment = "Center",
95
+ padding = 0.9,
96
+ rem = rem,
97
+ })), if text ~= "" and text then (React.createElement(Text, {
98
+ text = text,
99
+ size = UDim2.new(0, rem(2), 0, rem(2)),
100
+ textColor = textColor,
101
+ textXAlignment = "Left",
102
+ change = {
103
+ TextBounds = function(rbx)
104
+ textWidthMotion:spring({
105
+ value = rbx.TextBounds.X,
106
+ })
107
+ end,
108
+ },
109
+ })) else nil)
110
+ end
111
+ return {
112
+ Checkbox = Checkbox,
113
+ }
@@ -0,0 +1,14 @@
1
+ import React from "@rbxts/react";
2
+ import { type Theme } from "./theme";
3
+ interface CheckboxRowProps {
4
+ label: string;
5
+ checked: boolean;
6
+ onChecked: () => void;
7
+ disabled?: boolean;
8
+ name?: string;
9
+ children?: React.ReactNode;
10
+ theme?: Theme;
11
+ }
12
+ export declare function CheckboxRow({ label, checked, onChecked, disabled, name, children, theme, }: CheckboxRowProps): JSX.Element;
13
+ export type { CheckboxRowProps };
14
+ //# sourceMappingURL=CheckboxRow.d.ts.map
@@ -0,0 +1,52 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local React = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
+ local useRem = TS.import(script, TS.getModule(script, "@rbxts-ui", "rem").dist).useRem
5
+ local Checkbox = TS.import(script, script.Parent, "Checkbox").Checkbox
6
+ local Button = TS.import(script, script.Parent, "Button").Button
7
+ local HStack = TS.import(script, TS.getModule(script, "@rbxts-ui", "layout").dist).HStack
8
+ local Text = TS.import(script, TS.getModule(script, "@rbxts-ui", "primitives").dist).Text
9
+ local defaultTheme = TS.import(script, script.Parent, "theme").defaultTheme
10
+ local function CheckboxRow(_param)
11
+ local label = _param.label
12
+ local checked = _param.checked
13
+ local onChecked = _param.onChecked
14
+ local disabled = _param.disabled
15
+ if disabled == nil then
16
+ disabled = false
17
+ end
18
+ local name = _param.name
19
+ local children = _param.children
20
+ local theme = _param.theme
21
+ if theme == nil then
22
+ theme = defaultTheme
23
+ end
24
+ local rem = useRem()
25
+ local textSize = rem(3)
26
+ return React.createElement(HStack, {
27
+ size = UDim2.new(1, 0, 0, 0),
28
+ automaticSize = Enum.AutomaticSize.Y,
29
+ spacing = rem(2),
30
+ name = name,
31
+ }, React.createElement(Checkbox, {
32
+ checked = checked,
33
+ variant = "large",
34
+ onChecked = onChecked,
35
+ disabled = disabled,
36
+ theme = theme,
37
+ }), React.createElement(Button, {
38
+ backgroundTransparency = 1,
39
+ size = UDim2.new(1, 0, 0, rem(4)),
40
+ onClick = if disabled then function() end else onChecked,
41
+ }, React.createElement(Text, {
42
+ text = label,
43
+ textSize = textSize,
44
+ textScaled = true,
45
+ textColor = if disabled then theme.palette.overlay0 else theme.palette.crust,
46
+ size = UDim2.new(1, 0, 1, 0),
47
+ textXAlignment = "Left",
48
+ })), children)
49
+ end
50
+ return {
51
+ CheckboxRow = CheckboxRow,
52
+ }
@@ -0,0 +1,11 @@
1
+ import React from "@rbxts/react";
2
+ interface ClickOutsideOverlayProps {
3
+ readonly onClickOutside: () => void;
4
+ }
5
+ export declare function ClickOutsideOverlay({ onClickOutside }: ClickOutsideOverlayProps): JSX.Element;
6
+ interface ClickOutsideLayerProps extends React.PropsWithChildren {
7
+ readonly onClickOutside: () => void;
8
+ }
9
+ export declare function ClickOutsideLayer({ onClickOutside, children }: ClickOutsideLayerProps): JSX.Element;
10
+ export type { ClickOutsideOverlayProps, ClickOutsideLayerProps };
11
+ //# sourceMappingURL=ClickOutsideOverlay.d.ts.map
@@ -0,0 +1,35 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local React = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
+ local Frame = TS.import(script, TS.getModule(script, "@rbxts-ui", "primitives").dist).Frame
5
+ local function ClickOutsideOverlay(_param)
6
+ local onClickOutside = _param.onClickOutside
7
+ return React.createElement(Frame, {
8
+ size = UDim2.new(1, 0, 1, 0),
9
+ backgroundTransparency = 1,
10
+ active = true,
11
+ event = {
12
+ InputBegan = function(_, input)
13
+ if input.UserInputType ~= Enum.UserInputType.MouseButton1 and input.UserInputType ~= Enum.UserInputType.Touch then
14
+ return nil
15
+ end
16
+ onClickOutside()
17
+ end,
18
+ },
19
+ })
20
+ end
21
+ local function ClickOutsideLayer(_param)
22
+ local onClickOutside = _param.onClickOutside
23
+ local children = _param.children
24
+ return React.createElement(Frame, {
25
+ size = UDim2.new(1, 0, 1, 0),
26
+ backgroundTransparency = 1,
27
+ active = true,
28
+ }, React.createElement(ClickOutsideOverlay, {
29
+ onClickOutside = onClickOutside,
30
+ }), children)
31
+ end
32
+ return {
33
+ ClickOutsideOverlay = ClickOutsideOverlay,
34
+ ClickOutsideLayer = ClickOutsideLayer,
35
+ }
@@ -0,0 +1,18 @@
1
+ import React from "@rbxts/react";
2
+ import { type Theme } from "./theme";
3
+ interface DropdownOption<T> {
4
+ label: string;
5
+ value: T;
6
+ }
7
+ interface DropdownProps<T> {
8
+ options: Array<DropdownOption<T>>;
9
+ value?: T;
10
+ onChange: (value: T) => void;
11
+ size?: UDim2;
12
+ renderOption?: (option: DropdownOption<T>) => React.ReactNode;
13
+ portalRef?: React.RefObject<GuiObject>;
14
+ theme?: Theme;
15
+ }
16
+ export declare function Dropdown<T>(props: DropdownProps<T>): JSX.Element;
17
+ export type { DropdownOption, DropdownProps };
18
+ //# sourceMappingURL=Dropdown.d.ts.map
@@ -0,0 +1,160 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local VStackScrolling = TS.import(script, TS.getModule(script, "@rbxts-ui", "layout").dist).VStackScrolling
4
+ local Frame = TS.import(script, TS.getModule(script, "@rbxts-ui", "primitives").dist).Frame
5
+ local useRem = TS.import(script, TS.getModule(script, "@rbxts-ui", "rem").dist).useRem
6
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
7
+ local React = _react
8
+ local useEffect = _react.useEffect
9
+ local useRef = _react.useRef
10
+ local useState = _react.useState
11
+ local createPortal = TS.import(script, TS.getModule(script, "@rbxts", "react-roblox")).createPortal
12
+ local ClickOutsideLayer = TS.import(script, script.Parent, "ClickOutsideOverlay").ClickOutsideLayer
13
+ local DropdownButton = TS.import(script, script.Parent, "DropdownButton").DropdownButton
14
+ local DropdownOptionButton = TS.import(script, script.Parent, "DropdownOptionButton").DropdownOptionButton
15
+ local defaultTheme = TS.import(script, script.Parent, "theme").defaultTheme
16
+ local function Dropdown(props)
17
+ local _binding = props
18
+ local options = _binding.options
19
+ local value = _binding.value
20
+ local onChange = _binding.onChange
21
+ local size = _binding.size
22
+ local renderOption = _binding.renderOption
23
+ local portalRef = _binding.portalRef
24
+ local theme = _binding.theme
25
+ if theme == nil then
26
+ theme = defaultTheme
27
+ end
28
+ local isOpen, setIsOpen = useState(false)
29
+ local dropdownBounds, setDropdownBounds = useState()
30
+ local dropdownRef = useRef()
31
+ local rem = useRem()
32
+ local frameSize = size or UDim2.new(0.4, 0, 0, rem(5))
33
+ local optionHeight = rem(5)
34
+ -- ▼ ReadonlyArray.find ▼
35
+ local _callback = function(option)
36
+ return option.value == value
37
+ end
38
+ local _result
39
+ for _i, _v in options do
40
+ if _callback(_v, _i - 1, options) == true then
41
+ _result = _v
42
+ break
43
+ end
44
+ end
45
+ -- ▲ ReadonlyArray.find ▲
46
+ local selectedOption = _result
47
+ local cornerRadius = UDim.new(0, rem(1.7))
48
+ local dropdownHeight = #options * optionHeight
49
+ useEffect(function()
50
+ if not isOpen then
51
+ setDropdownBounds(nil)
52
+ return nil
53
+ end
54
+ local frame = dropdownRef.current
55
+ if not frame then
56
+ return nil
57
+ end
58
+ local updateBounds = function()
59
+ setDropdownBounds({
60
+ position = frame.AbsolutePosition,
61
+ size = frame.AbsoluteSize,
62
+ })
63
+ end
64
+ updateBounds()
65
+ local positionConnection = frame:GetPropertyChangedSignal("AbsolutePosition"):Connect(updateBounds)
66
+ local sizeConnection = frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateBounds)
67
+ return function()
68
+ positionConnection:Disconnect()
69
+ sizeConnection:Disconnect()
70
+ end
71
+ end, { isOpen })
72
+ local renderOptions = function()
73
+ local _exp = React.createElement("uicorner", {
74
+ CornerRadius = cornerRadius,
75
+ })
76
+ local _exp_1 = React.createElement("uistroke", {
77
+ Color = theme.palette.crust,
78
+ Transparency = 0.5,
79
+ Thickness = 1,
80
+ })
81
+ -- ▼ ReadonlyArray.map ▼
82
+ local _newValue = table.create(#options)
83
+ local _callback_1 = function(option)
84
+ return React.createElement(DropdownOptionButton, {
85
+ key = tostring(option.value),
86
+ text = option.label,
87
+ size = UDim2.new(1, 0, 0, optionHeight),
88
+ onClick = function()
89
+ onChange(option.value)
90
+ setIsOpen(false)
91
+ end,
92
+ theme = theme,
93
+ }, if renderOption then renderOption(option) else nil)
94
+ end
95
+ for _k, _v in options do
96
+ _newValue[_k] = _callback_1(_v, _k - 1, options)
97
+ end
98
+ -- ▲ ReadonlyArray.map ▲
99
+ return React.createElement(React.Fragment, nil, _exp, _exp_1, _newValue)
100
+ end
101
+ local dropdownOverlay = (function()
102
+ if not isOpen then
103
+ return nil
104
+ end
105
+ -- Use provided portalRef or fallback to Players.LocalPlayer.PlayerGui
106
+ local _container = portalRef
107
+ if _container ~= nil then
108
+ _container = _container.current
109
+ end
110
+ local container = _container
111
+ if not container then
112
+ error("Dropdown requires a portalRef prop or a PortalProvider with an active portalRef")
113
+ end
114
+ if not dropdownBounds then
115
+ return nil
116
+ end
117
+ local containerPosition = container.AbsolutePosition
118
+ local relativePosition = dropdownBounds.position - containerPosition
119
+ local dropdownY = relativePosition.Y + dropdownBounds.size.Y
120
+ return createPortal(React.createElement(ClickOutsideLayer, {
121
+ onClickOutside = function()
122
+ return setIsOpen(false)
123
+ end,
124
+ }, React.createElement(VStackScrolling, {
125
+ Position = UDim2.new(0, relativePosition.X, 0, dropdownY),
126
+ Size = UDim2.new(0, dropdownBounds.size.X, 0, dropdownHeight),
127
+ BackgroundColor3 = theme.palette.white,
128
+ BackgroundTransparency = 0,
129
+ ClipsDescendants = true,
130
+ BorderColor3 = theme.palette.crust,
131
+ ZIndex = 2000,
132
+ paddingBottom = rem(1),
133
+ }, renderOptions())), container)
134
+ end)()
135
+ local _attributes = {}
136
+ local _result_1 = selectedOption
137
+ if _result_1 ~= nil then
138
+ _result_1 = _result_1.label
139
+ end
140
+ local _condition = _result_1
141
+ if not (_condition ~= "" and _condition) then
142
+ _condition = "Select..."
143
+ end
144
+ _attributes.text = _condition
145
+ _attributes.size = UDim2.new(1, 0, 1, 0)
146
+ _attributes.onClick = function()
147
+ return setIsOpen(not isOpen)
148
+ end
149
+ _attributes.theme = theme
150
+ return React.createElement(Frame, {
151
+ backgroundTransparency = 1,
152
+ size = frameSize,
153
+ ref = dropdownRef,
154
+ }, React.createElement(DropdownButton, _attributes), dropdownOverlay, React.createElement("uiflexitem", {
155
+ FlexMode = Enum.UIFlexMode.Fill,
156
+ }))
157
+ end
158
+ return {
159
+ Dropdown = Dropdown,
160
+ }
@@ -0,0 +1,22 @@
1
+ import React from "@rbxts/react";
2
+ import { type Theme } from "./theme";
3
+ interface DropdownButtonProps extends React.PropsWithChildren {
4
+ readonly text: string;
5
+ readonly onClick?: () => void;
6
+ readonly onHover?: (hovered: boolean) => void;
7
+ readonly size?: UDim2 | React.Binding<UDim2>;
8
+ readonly position?: UDim2 | React.Binding<UDim2>;
9
+ readonly anchorPoint?: Vector2 | React.Binding<Vector2>;
10
+ readonly overlayGradient?: ColorSequence | React.Binding<ColorSequence>;
11
+ readonly overlayTransparency?: number | React.Binding<number>;
12
+ readonly overlayRotation?: number | React.Binding<number>;
13
+ readonly layoutOrder?: number | React.Binding<number>;
14
+ readonly isDisabled?: boolean;
15
+ readonly hasShadow?: boolean;
16
+ readonly padding?: number;
17
+ readonly radius?: number;
18
+ readonly theme?: Theme;
19
+ }
20
+ export declare function DropdownButton({ text, onClick, onHover, position, anchorPoint, layoutOrder, isDisabled, size, padding, radius, theme, }: DropdownButtonProps): JSX.Element;
21
+ export type { DropdownButtonProps };
22
+ //# sourceMappingURL=DropdownButton.d.ts.map