@rbxts/react-clean-ui 1.2.2 → 1.2.5
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/out/Components/Chart/Pie.luau +0 -1
- package/out/Components/Decorator/Gradient.d.ts +8 -0
- package/out/Components/Decorator/Gradient.luau +23 -0
- package/out/Components/Decorator/index.d.ts +1 -0
- package/out/Components/Decorator/init.luau +3 -0
- package/out/Components/Input/Button.luau +5 -1
- package/out/Components/Input/Checkbox.luau +6 -2
- package/out/Components/Input/HoverButton.luau +0 -2
- package/out/Components/Input/Input.luau +8 -6
- package/out/Components/Input/Select.d.ts +2 -1
- package/out/Components/Input/Select.luau +10 -11
- package/out/Components/Input/Slider.luau +0 -24
- package/out/Components/Input/Switch.luau +0 -2
- package/out/Components/Interaction/Modal.luau +0 -14
- package/out/Components/Interaction/Tooltip.luau +0 -1
- package/out/Components/Layout/Container.d.ts +2 -0
- package/out/Components/Layout/Container.luau +4 -1
- package/out/Components/Layout/Grid.d.ts +10 -0
- package/out/Components/Layout/Grid.luau +172 -0
- package/out/Components/Layout/Group.luau +38 -33
- package/out/Components/Layout/Pagination.luau +0 -5
- package/out/Components/Layout/Tabs.d.ts +2 -1
- package/out/Components/Layout/Tabs.luau +12 -33
- package/out/Components/Layout/index.d.ts +1 -0
- package/out/Components/Layout/init.luau +3 -0
- package/out/Components/Surface/Box.d.ts +2 -1
- package/out/Components/Surface/Box.luau +3 -0
- package/out/Components/Surface/Card.luau +54 -111
- package/out/Components/Surface/ProgressBar.d.ts +14 -0
- package/out/Components/Surface/ProgressBar.luau +230 -0
- package/out/Components/Surface/index.d.ts +1 -0
- package/out/Components/Surface/init.luau +3 -0
- package/out/Components/Typography/Text.luau +0 -6
- package/out/Contexts/modal.context.luau +0 -3
- package/out/Helpers/color.helper.luau +28 -0
- package/out/Helpers/css.helper.d.ts +4 -1
- package/out/Helpers/css.helper.luau +76 -6
- package/out/Helpers/gui.helper.luau +0 -3
- package/out/Helpers/size.helper.luau +0 -2
- package/out/Helpers/spacing.helper.luau +0 -3
- package/out/Helpers/typography.helper.luau +0 -2
- package/out/Interfaces/css.types.d.ts +7 -0
- package/out/Interfaces/css.types.luau +0 -20
- package/out/Providers/registry.provider.luau +0 -2
- package/out/Theme/theme.style.d.ts +8 -1
- package/out/Theme/theme.template.d.ts +44 -2
- package/out/Theme/themes/dark.theme.luau +122 -0
- package/out/Theme/themes/default.theme.luau +80 -0
- package/out/Theme/themes/sandstone.theme.luau +70 -0
- package/out/Theme/themes/wooden.theme.luau +73 -0
- package/package.json +1 -1
|
@@ -60,7 +60,6 @@ local function getCirclePosition(normalized, radius)
|
|
|
60
60
|
end
|
|
61
61
|
local centerX = 0.5
|
|
62
62
|
local centerY = 0.5
|
|
63
|
-
-- Convert 0 → 1 into radians (0 → 2π)
|
|
64
63
|
local angle = normalized * math.pi * 2 + math.pi
|
|
65
64
|
local x = centerX + math.cos(angle) * radius
|
|
66
65
|
local y = centerY + math.sin(angle) * radius
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "@rbxts/react";
|
|
2
|
+
import { CssBackgroundGradient } from "../../Interfaces/";
|
|
3
|
+
interface GradientProps {
|
|
4
|
+
value?: Partial<CssBackgroundGradient>;
|
|
5
|
+
name?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function Gradient(props: GradientProps): React.JSX.Element | undefined;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
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 CssHelper = TS.import(script, script.Parent.Parent.Parent, "Helpers").CssHelper
|
|
5
|
+
local function Gradient(props)
|
|
6
|
+
local resolved = CssHelper:resolveBackgroundGradient(props.value)
|
|
7
|
+
if resolved == nil then
|
|
8
|
+
return nil
|
|
9
|
+
end
|
|
10
|
+
local _attributes = {}
|
|
11
|
+
local _condition = props.name
|
|
12
|
+
if _condition == nil then
|
|
13
|
+
_condition = "Gradient"
|
|
14
|
+
end
|
|
15
|
+
_attributes.key = _condition
|
|
16
|
+
for _k, _v in resolved do
|
|
17
|
+
_attributes[_k] = _v
|
|
18
|
+
end
|
|
19
|
+
return React.createElement("uigradient", _attributes)
|
|
20
|
+
end
|
|
21
|
+
return {
|
|
22
|
+
Gradient = Gradient,
|
|
23
|
+
}
|
|
@@ -7,6 +7,9 @@ end
|
|
|
7
7
|
for _k, _v in TS.import(script, script, "Corners") or {} do
|
|
8
8
|
exports[_k] = _v
|
|
9
9
|
end
|
|
10
|
+
for _k, _v in TS.import(script, script, "Gradient") or {} do
|
|
11
|
+
exports[_k] = _v
|
|
12
|
+
end
|
|
10
13
|
for _k, _v in TS.import(script, script, "Padding") or {} do
|
|
11
14
|
exports[_k] = _v
|
|
12
15
|
end
|
|
@@ -5,6 +5,7 @@ local CleanThemeContext = TS.import(script, script.Parent.Parent.Parent, "Contex
|
|
|
5
5
|
local _Decorator = TS.import(script, script.Parent.Parent, "Decorator")
|
|
6
6
|
local BoxShadow = _Decorator.BoxShadow
|
|
7
7
|
local Corners = _Decorator.Corners
|
|
8
|
+
local Gradient = _Decorator.Gradient
|
|
8
9
|
local Padding = _Decorator.Padding
|
|
9
10
|
local Text = TS.import(script, script.Parent.Parent, "Typography").Text
|
|
10
11
|
local _Helpers = TS.import(script, script.Parent.Parent.Parent, "Helpers")
|
|
@@ -224,9 +225,12 @@ local Button = React.forwardRef(function(props, ref)
|
|
|
224
225
|
end
|
|
225
226
|
_attributes_3.value = _condition_4
|
|
226
227
|
local _exp_4 = React.createElement(BoxShadow, _attributes_3)
|
|
228
|
+
local _exp_5 = React.createElement(Gradient, {
|
|
229
|
+
value = intentColors.backgroundGradient,
|
|
230
|
+
})
|
|
227
231
|
local _attributes_4 = table.clone(props)
|
|
228
232
|
setmetatable(_attributes_4, nil)
|
|
229
|
-
return React.createElement("imagebutton", _attributes, _exp_2, _exp_3, _exp_4, React.createElement(Padding, _attributes_4), React.createElement(Group.Element, {
|
|
233
|
+
return React.createElement("imagebutton", _attributes, _exp_2, _exp_3, _exp_4, _exp_5, React.createElement(Padding, _attributes_4), React.createElement(Group.Element, {
|
|
230
234
|
enabled = props.group,
|
|
231
235
|
padding = padding,
|
|
232
236
|
}, (props.icon ~= nil or props.text ~= nil) and React.createElement(HStack, {
|
|
@@ -6,6 +6,7 @@ local CleanThemeContext = TS.import(script, script.Parent.Parent.Parent, "Contex
|
|
|
6
6
|
local FieldsetContext = TS.import(script, script.Parent.Parent, "Layout").FieldsetContext
|
|
7
7
|
local _Decorator = TS.import(script, script.Parent.Parent, "Decorator")
|
|
8
8
|
local Corners = _Decorator.Corners
|
|
9
|
+
local Gradient = _Decorator.Gradient
|
|
9
10
|
local Padding = _Decorator.Padding
|
|
10
11
|
local _Helpers = TS.import(script, script.Parent.Parent.Parent, "Helpers")
|
|
11
12
|
local ColorHelper = _Helpers.ColorHelper
|
|
@@ -64,7 +65,7 @@ local function Checkbox(props)
|
|
|
64
65
|
_condition_2 = theme.components.button.backgroundTransparency
|
|
65
66
|
end
|
|
66
67
|
_attributes.BackgroundTransparency = _condition_2
|
|
67
|
-
_attributes.BackgroundColor3 = ColorHelper:getIntentColors(theme, props.intent, "default", theme.components.
|
|
68
|
+
_attributes.BackgroundColor3 = ColorHelper:getIntentColors(theme, props.intent, "default", theme.components.checkbox.intents).backgroundColor
|
|
68
69
|
_attributes.AutoButtonColor = false
|
|
69
70
|
_attributes.Image = backgroundImage.Image
|
|
70
71
|
_attributes.ImageColor3 = backgroundImage.ImageColor3
|
|
@@ -76,6 +77,9 @@ local function Checkbox(props)
|
|
|
76
77
|
local _exp = React.createElement(Corners, {
|
|
77
78
|
radius = theme.components.checkbox.cornerRadius,
|
|
78
79
|
})
|
|
80
|
+
local _exp_1 = React.createElement(Gradient, {
|
|
81
|
+
value = theme.components.checkbox.backgroundGradient,
|
|
82
|
+
})
|
|
79
83
|
local _attributes_1 = {
|
|
80
84
|
key = "Stroke",
|
|
81
85
|
Thickness = theme.components.checkbox.borderThickness,
|
|
@@ -87,7 +91,7 @@ local function Checkbox(props)
|
|
|
87
91
|
end
|
|
88
92
|
_attributes_1.Transparency = _condition_3
|
|
89
93
|
_attributes_1.Color = ColorHelper:getIntentColors(theme, if checked then props["intent-checked"] or "success" else props["intent-unchecked"] or "primary", "default", theme.components.checkbox.intents).borderColor
|
|
90
|
-
return React.createElement("imagebutton", _attributes, _exp, React.createElement("uistroke", _attributes_1), React.createElement(Padding, {
|
|
94
|
+
return React.createElement("imagebutton", _attributes, _exp, _exp_1, React.createElement("uistroke", _attributes_1), React.createElement(Padding, {
|
|
91
95
|
resolvedPadding = SpacingHelper:GetResolvedPadding(theme, props, theme.components.checkbox.spacing, theme.components.checkbox.padding),
|
|
92
96
|
}), React.createElement(Icon, {
|
|
93
97
|
name = "CheckboxIcon",
|
|
@@ -6,8 +6,6 @@ local function HoverButton(propSet)
|
|
|
6
6
|
local hovering, setHovering = React.useState(false)
|
|
7
7
|
local state = if propSet.isSelected then "focus" elseif hovering then "hover" else "default"
|
|
8
8
|
local stateProps = propSet[state]
|
|
9
|
-
-- Object spreading into a new object is supported.
|
|
10
|
-
-- It is object rest destructuring that roblox-ts does not support.
|
|
11
9
|
local _object = table.clone(propSet.default)
|
|
12
10
|
setmetatable(_object, nil)
|
|
13
11
|
if stateProps then
|
|
@@ -10,6 +10,7 @@ local CssHelper = _Helpers.CssHelper
|
|
|
10
10
|
local TypographyHelper = _Helpers.TypographyHelper
|
|
11
11
|
local _Decorator = TS.import(script, script.Parent.Parent, "Decorator")
|
|
12
12
|
local Corners = _Decorator.Corners
|
|
13
|
+
local Gradient = _Decorator.Gradient
|
|
13
14
|
local Padding = _Decorator.Padding
|
|
14
15
|
local _Layout = TS.import(script, script.Parent.Parent, "Layout")
|
|
15
16
|
local FieldsetContext = _Layout.FieldsetContext
|
|
@@ -31,8 +32,6 @@ local function Input(props)
|
|
|
31
32
|
local value, setValue = useState(props.value)
|
|
32
33
|
local lastValidText = useRef(props.value)
|
|
33
34
|
local typography = TypographyHelper:getTypography(theme, props.scale, theme.components.input.typography)
|
|
34
|
-
-- Roblox's TextBox has no PlaceholderTransparency and shares font/size/weight/lineHeight
|
|
35
|
-
-- between Text and PlaceholderText, so only `.color` from this resolution is actually used below.
|
|
36
35
|
local placeholderTypography = TypographyHelper:getTypography(theme, props.scale, theme.components.input.placeholder)
|
|
37
36
|
local backgroundImage = CssHelper:resolveBackgroundImage(theme.components.input.backgroundImage)
|
|
38
37
|
React.useEffect(function()
|
|
@@ -79,10 +78,13 @@ local function Input(props)
|
|
|
79
78
|
local _exp_1 = React.createElement(Corners, {
|
|
80
79
|
radius = theme.components.input.cornerRadius,
|
|
81
80
|
})
|
|
81
|
+
local _exp_2 = React.createElement(Gradient, {
|
|
82
|
+
value = theme.components.input.backgroundGradient,
|
|
83
|
+
})
|
|
82
84
|
local _attributes_1 = table.clone(props)
|
|
83
85
|
setmetatable(_attributes_1, nil)
|
|
84
|
-
local
|
|
85
|
-
local
|
|
86
|
+
local _exp_3 = React.createElement(Padding, _attributes_1)
|
|
87
|
+
local _exp_4 = props.icon ~= nil and (React.createElement(Icon, {
|
|
86
88
|
name = "InputIcon",
|
|
87
89
|
icon = props.icon,
|
|
88
90
|
color = theme.components.input.iconColor,
|
|
@@ -198,10 +200,10 @@ local function Input(props)
|
|
|
198
200
|
end
|
|
199
201
|
end
|
|
200
202
|
_attributes_2.Change = _object_1
|
|
201
|
-
return React.createElement("imagelabel", _attributes, _exp, _exp_1, _exp_2, React.createElement(HStack, {
|
|
203
|
+
return React.createElement("imagelabel", _attributes, _exp, _exp_1, _exp_2, _exp_3, React.createElement(HStack, {
|
|
202
204
|
valign = "Center",
|
|
203
205
|
Wraps = false,
|
|
204
|
-
},
|
|
206
|
+
}, _exp_4, React.createElement(FlexItem, nil, React.createElement("textbox", _attributes_2))))
|
|
205
207
|
end
|
|
206
208
|
return {
|
|
207
209
|
Input = Input,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React from "@rbxts/react";
|
|
2
|
-
import { CssSize, ScalableElementProps, SpacedElementProps } from "../../Interfaces";
|
|
2
|
+
import { CssBackgroundGradient, CssSize, ScalableElementProps, SpacedElementProps } from "../../Interfaces";
|
|
3
3
|
import { CssBackgroundImage } from "../../Theme";
|
|
4
4
|
export interface SelectProps extends ScalableElementProps, SpacedElementProps, React.InstanceProps<ImageLabel> {
|
|
5
5
|
selected?: number;
|
|
6
6
|
'max-height'?: CssSize;
|
|
7
7
|
backgroundImage?: CssBackgroundImage;
|
|
8
|
+
backgroundGradient?: CssBackgroundGradient;
|
|
8
9
|
onChange?: (selected: number, value?: string) => void;
|
|
9
10
|
name?: string;
|
|
10
11
|
searchable?: boolean;
|
|
@@ -12,6 +12,7 @@ local SpacingHelper = _Helpers.SpacingHelper
|
|
|
12
12
|
local TypographyHelper = _Helpers.TypographyHelper
|
|
13
13
|
local _Decorator = TS.import(script, script.Parent.Parent, "Decorator")
|
|
14
14
|
local Corners = _Decorator.Corners
|
|
15
|
+
local Gradient = _Decorator.Gradient
|
|
15
16
|
local Padding = _Decorator.Padding
|
|
16
17
|
local _Layout = TS.import(script, script.Parent.Parent, "Layout")
|
|
17
18
|
local Container = _Layout.Container
|
|
@@ -89,9 +90,6 @@ local function parseSelectChildren(children)
|
|
|
89
90
|
local index = 0
|
|
90
91
|
local nodeCount = 0
|
|
91
92
|
local groupCount = 0
|
|
92
|
-
-- Fragment-wrapped children (`<>...</>`) are unwrapped/recursed into so
|
|
93
|
-
-- consumers can conditionally compose Option/OptGroup lists (a common
|
|
94
|
-
-- React pattern) without breaking option indexing.
|
|
95
93
|
local collectGroupOptions
|
|
96
94
|
collectGroupOptions = function(node, options)
|
|
97
95
|
React.Children.forEach(node, function(groupChild)
|
|
@@ -178,8 +176,6 @@ local function optionMatchesQuery(option, normalizedQuery)
|
|
|
178
176
|
if option.text == nil then
|
|
179
177
|
return true
|
|
180
178
|
end
|
|
181
|
-
-- Plain-text/literal find (the trailing `true`) avoids treating Lua
|
|
182
|
-
-- pattern characters in the query (e.g. `%`, `-`) as patterns.
|
|
183
179
|
local _exp = string.lower(option.text)
|
|
184
180
|
local _normalizedQuery = normalizedQuery
|
|
185
181
|
return (string.find(_exp, _normalizedQuery, 1, true)) ~= nil
|
|
@@ -437,18 +433,21 @@ local Select = React.forwardRef(function(props, ref)
|
|
|
437
433
|
_attributes.Size = UDim2.fromScale(1, 0)
|
|
438
434
|
_attributes.AutomaticSize = Enum.AutomaticSize.Y
|
|
439
435
|
_attributes.backgroundImage = props.backgroundImage or theme.components.select.backgroundImage
|
|
440
|
-
local _exp_1 = React.createElement(
|
|
436
|
+
local _exp_1 = React.createElement(Gradient, {
|
|
437
|
+
value = props.backgroundGradient or theme.components.select.backgroundGradient,
|
|
438
|
+
})
|
|
439
|
+
local _exp_2 = React.createElement("uistroke", {
|
|
441
440
|
key = "Stroke",
|
|
442
441
|
Thickness = theme.components.select.borderThickness,
|
|
443
442
|
BorderStrokePosition = Enum.BorderStrokePosition.Inner,
|
|
444
443
|
Color = theme.components.select.borderColor,
|
|
445
444
|
})
|
|
446
|
-
local
|
|
445
|
+
local _exp_3 = React.createElement(Corners, {
|
|
447
446
|
radius = theme.components.select.cornerRadius,
|
|
448
447
|
})
|
|
449
448
|
local _attributes_1 = table.clone(props)
|
|
450
449
|
setmetatable(_attributes_1, nil)
|
|
451
|
-
local
|
|
450
|
+
local _exp_4 = React.createElement(Padding, _attributes_1)
|
|
452
451
|
local _attributes_2 = {
|
|
453
452
|
name = "SelectedText",
|
|
454
453
|
}
|
|
@@ -462,7 +461,7 @@ local Select = React.forwardRef(function(props, ref)
|
|
|
462
461
|
end
|
|
463
462
|
_attributes_2.text = _condition_4
|
|
464
463
|
_attributes_2.typography = typography
|
|
465
|
-
local
|
|
464
|
+
local _exp_5 = React.createElement(HStack, nil, React.createElement(FlexItem, nil, React.createElement(Text, _attributes_2)), React.createElement(Icon, {
|
|
466
465
|
name = "SelectCaret",
|
|
467
466
|
icon = "caret-down",
|
|
468
467
|
color = theme.colors.intents.primary.default.textColor,
|
|
@@ -510,7 +509,7 @@ local Select = React.forwardRef(function(props, ref)
|
|
|
510
509
|
typography = typography,
|
|
511
510
|
}))))), overlay.overlay)
|
|
512
511
|
end
|
|
513
|
-
return React.createElement(Container, _attributes, React.createElement(SelectContext.Provider, {
|
|
512
|
+
return React.createElement(Container, _attributes, _exp_1, React.createElement(SelectContext.Provider, {
|
|
514
513
|
value = context,
|
|
515
514
|
}, React.createElement("imagebutton", {
|
|
516
515
|
key = "SelectButton",
|
|
@@ -521,7 +520,7 @@ local Select = React.forwardRef(function(props, ref)
|
|
|
521
520
|
Event = {
|
|
522
521
|
Activated = activateSelect,
|
|
523
522
|
},
|
|
524
|
-
},
|
|
523
|
+
}, _exp_2, _exp_3, _exp_4, _exp_5, _condition_5)))
|
|
525
524
|
end)
|
|
526
525
|
Select.Option = SelectOption
|
|
527
526
|
Select.OptGroup = SelectOptGroup
|
|
@@ -68,11 +68,6 @@ local Slider = React.forwardRef(function(props, ref)
|
|
|
68
68
|
end
|
|
69
69
|
setValue(nextValue)
|
|
70
70
|
end, {})
|
|
71
|
-
--[[
|
|
72
|
-
*
|
|
73
|
-
* Converts an input position into a single slider value.
|
|
74
|
-
|
|
75
|
-
]]
|
|
76
71
|
local getNumberFromInput = React.useCallback(function(input)
|
|
77
72
|
local container = containerRef.current
|
|
78
73
|
if not container then
|
|
@@ -95,14 +90,7 @@ local Slider = React.forwardRef(function(props, ref)
|
|
|
95
90
|
local nextValue = minValue + percentage * (maxValue - minValue)
|
|
96
91
|
local step = currentProps.step
|
|
97
92
|
if step ~= nil and step > 0 then
|
|
98
|
-
--[[
|
|
99
|
-
|
|
100
|
-
* Offset snapping from minValue so ranges such as
|
|
101
|
-
* min=5, step=2 produce 5, 7, 9, etc.
|
|
102
|
-
|
|
103
|
-
]]
|
|
104
93
|
nextValue = minValue + math.round((nextValue - minValue) / step) * step
|
|
105
|
-
-- Remove floating-point artifacts.
|
|
106
94
|
local parts = string.split(tostring(step), ".")
|
|
107
95
|
local decimals = if #parts > 1 then #parts[2] else 0
|
|
108
96
|
local scale = 10 ^ decimals
|
|
@@ -110,12 +98,6 @@ local Slider = React.forwardRef(function(props, ref)
|
|
|
110
98
|
end
|
|
111
99
|
return math.clamp(nextValue, minValue, maxValue)
|
|
112
100
|
end, {})
|
|
113
|
-
--[[
|
|
114
|
-
*
|
|
115
|
-
* Converts a single input value into either a number or Vector2,
|
|
116
|
-
* depending on whether range mode is enabled.
|
|
117
|
-
|
|
118
|
-
]]
|
|
119
101
|
local getValueFromInput = React.useCallback(function(input)
|
|
120
102
|
local inputValue = getNumberFromInput(input)
|
|
121
103
|
if inputValue == nil then
|
|
@@ -186,12 +168,6 @@ local Slider = React.forwardRef(function(props, ref)
|
|
|
186
168
|
if not isDraggingRef.current then
|
|
187
169
|
return nil
|
|
188
170
|
end
|
|
189
|
-
--[[
|
|
190
|
-
|
|
191
|
-
* Stop processing movement immediately, before
|
|
192
|
-
* React gets around to updating the state.
|
|
193
|
-
|
|
194
|
-
]]
|
|
195
171
|
isDraggingRef.current = false
|
|
196
172
|
local nextValue = getValueFromInput(input)
|
|
197
173
|
activeHandleRef.current = nil
|
|
@@ -10,8 +10,6 @@ local BoxShadow = _Decorator.BoxShadow
|
|
|
10
10
|
local _Helpers = TS.import(script, script.Parent.Parent.Parent, "Helpers")
|
|
11
11
|
local ColorHelper = _Helpers.ColorHelper
|
|
12
12
|
local SizeHelper = _Helpers.SizeHelper
|
|
13
|
-
-- Linearly interpolates between two UDim values by treating Scale and Offset
|
|
14
|
-
-- as independent components, since UDim itself has no Lerp method.
|
|
15
13
|
local function lerpUDim(from, to, alpha)
|
|
16
14
|
return UDim.new(from.Scale + (to.Scale - from.Scale) * alpha, from.Offset + (to.Offset - from.Offset) * alpha)
|
|
17
15
|
end
|
|
@@ -18,10 +18,6 @@ local function generateModalId()
|
|
|
18
18
|
nextModalId += 1
|
|
19
19
|
return `modal-{nextModalId}`
|
|
20
20
|
end
|
|
21
|
-
-- GuiService.SelectedObject can only be set to a descendant of a PlayerGui —
|
|
22
|
-
-- it throws otherwise (e.g. a ui-labs Studio plugin preview, or any other
|
|
23
|
-
-- non-PlayerGui host). Focus is a non-essential enhancement, so failures here
|
|
24
|
-
-- are swallowed rather than crashing the whole render.
|
|
25
21
|
local function trySetSelectedObject(target)
|
|
26
22
|
pcall(function()
|
|
27
23
|
GuiService.SelectedObject = target
|
|
@@ -111,9 +107,6 @@ local function Modal(props)
|
|
|
111
107
|
setShouldRender(false)
|
|
112
108
|
end)
|
|
113
109
|
end, { fadeDuration })
|
|
114
|
-
-- Public open state vs. animated-unmount state: closing must finish its
|
|
115
|
-
-- fade before the portal actually disappears, so `shouldRender` lags
|
|
116
|
-
-- `open` on the way down (see beginExit above).
|
|
117
110
|
React.useEffect(function()
|
|
118
111
|
if open then
|
|
119
112
|
local fadeThread = fadeThreadRef.current
|
|
@@ -142,11 +135,6 @@ local function Modal(props)
|
|
|
142
135
|
end
|
|
143
136
|
end
|
|
144
137
|
end, {})
|
|
145
|
-
-- Registers with the shared modal stack only while actually visible
|
|
146
|
-
-- (including through the closing fade), so escape only ever targets the
|
|
147
|
-
-- topmost visible modal. closeOnEscape/requestClose are read through
|
|
148
|
-
-- refs kept current every render (see above) so this effect only needs
|
|
149
|
-
-- to run when shouldRender flips.
|
|
150
138
|
React.useEffect(function()
|
|
151
139
|
if not shouldRender then
|
|
152
140
|
return nil
|
|
@@ -164,8 +152,6 @@ local function Modal(props)
|
|
|
164
152
|
stack.unregister(id)
|
|
165
153
|
end
|
|
166
154
|
end, { shouldRender })
|
|
167
|
-
-- Scoped per-instance so nested modals restore focus to whatever was
|
|
168
|
-
-- selected right before THEY opened, not a single shared value.
|
|
169
155
|
React.useEffect(function()
|
|
170
156
|
if not shouldRender then
|
|
171
157
|
return nil
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from "@rbxts/react";
|
|
2
2
|
import { PositionElementProps, SizeElementProps, ZIndexElementProps } from "../../Interfaces/";
|
|
3
3
|
import { CssBackgroundImage } from "../../Theme";
|
|
4
|
+
import { CssBackgroundGradient } from "../../Interfaces/";
|
|
4
5
|
export interface ContainerProps extends SizeElementProps, PositionElementProps, ZIndexElementProps, React.InstanceProps<ImageLabel> {
|
|
5
6
|
group?: boolean;
|
|
6
7
|
backgroundImage?: Partial<CssBackgroundImage>;
|
|
8
|
+
backgroundGradient?: Partial<CssBackgroundGradient>;
|
|
7
9
|
name?: string;
|
|
8
10
|
}
|
|
9
11
|
export declare const Container: React.ForwardRefExoticComponent<Omit<ContainerProps, "ref"> & React.RefAttributes<ImageLabel>>;
|
|
@@ -4,6 +4,7 @@ local React = TS.import(script, TS.getModule(script, "@rbxts", "react"))
|
|
|
4
4
|
local _ = TS.import(script, script.Parent.Parent.Parent, "Helpers")
|
|
5
5
|
local SizeHelper = _.SizeHelper
|
|
6
6
|
local CssHelper = _.CssHelper
|
|
7
|
+
local Gradient = TS.import(script, script.Parent.Parent, "Decorator").Gradient
|
|
7
8
|
local _Group = TS.import(script, script.Parent, "Group")
|
|
8
9
|
local Group = _Group.Group
|
|
9
10
|
local GroupContext = _Group.GroupContext
|
|
@@ -80,7 +81,9 @@ local Container = React.forwardRef(function(props, ref)
|
|
|
80
81
|
_attributes.TileSize = backgroundImage.TileSize
|
|
81
82
|
_attributes.Change = props.Change
|
|
82
83
|
_attributes.Event = props.Event
|
|
83
|
-
local content = (React.createElement("imagelabel", _attributes, React.createElement(
|
|
84
|
+
local content = (React.createElement("imagelabel", _attributes, React.createElement(Gradient, {
|
|
85
|
+
value = props.backgroundGradient,
|
|
86
|
+
}), React.createElement(Group.Element, {
|
|
84
87
|
enabled = props.group,
|
|
85
88
|
}, props.children)))
|
|
86
89
|
if not centerViaLayout then
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "@rbxts/react";
|
|
2
|
+
import { BreakPointElementProps, ResponsiveCssSize, ResponsiveValue, ScaleSize } from "../../Interfaces/";
|
|
3
|
+
export interface GridProps extends BreakPointElementProps {
|
|
4
|
+
cols?: ResponsiveValue<number>;
|
|
5
|
+
gap?: ScaleSize | "None";
|
|
6
|
+
width?: ResponsiveCssSize;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
name?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<Frame>>;
|
|
@@ -0,0 +1,172 @@
|
|
|
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 CleanThemeContext = TS.import(script, script.Parent.Parent.Parent, "Contexts").CleanThemeContext
|
|
5
|
+
local _ = TS.import(script, script.Parent.Parent.Parent, "Helpers")
|
|
6
|
+
local BreakpointHelper = _.BreakpointHelper
|
|
7
|
+
local SizeHelper = _.SizeHelper
|
|
8
|
+
local SpacingHelper = _.SpacingHelper
|
|
9
|
+
local SETTLE_POLL_FRAMES = 10
|
|
10
|
+
local function GridCell(props)
|
|
11
|
+
local measurementRef = React.useRef()
|
|
12
|
+
local reportMeasurement = React.useCallback(function()
|
|
13
|
+
local instance = measurementRef.current
|
|
14
|
+
if instance ~= nil then
|
|
15
|
+
props.onMeasured(props.measureKey, props.index, instance.AbsoluteSize.Y)
|
|
16
|
+
end
|
|
17
|
+
end, { props.onMeasured, props.measureKey, props.index })
|
|
18
|
+
React.useEffect(function()
|
|
19
|
+
if props.locked then
|
|
20
|
+
return nil
|
|
21
|
+
end
|
|
22
|
+
local mounted = true
|
|
23
|
+
reportMeasurement()
|
|
24
|
+
task.spawn(function()
|
|
25
|
+
for frame = 0, SETTLE_POLL_FRAMES - 1 do
|
|
26
|
+
task.wait()
|
|
27
|
+
if not mounted then
|
|
28
|
+
return nil
|
|
29
|
+
end
|
|
30
|
+
reportMeasurement()
|
|
31
|
+
end
|
|
32
|
+
end)
|
|
33
|
+
return function()
|
|
34
|
+
mounted = false
|
|
35
|
+
end
|
|
36
|
+
end, { props.locked, props.measureKey, reportMeasurement })
|
|
37
|
+
return React.createElement("frame", {
|
|
38
|
+
key = "GridCell",
|
|
39
|
+
ref = measurementRef,
|
|
40
|
+
LayoutOrder = props.index,
|
|
41
|
+
Size = UDim2.new(props.width, UDim.new(0, if props.locked then props.height else 0)),
|
|
42
|
+
AutomaticSize = if props.locked then Enum.AutomaticSize.None else Enum.AutomaticSize.Y,
|
|
43
|
+
BackgroundTransparency = 1,
|
|
44
|
+
ClipsDescendants = true,
|
|
45
|
+
Change = if props.locked then nil else {
|
|
46
|
+
AbsoluteSize = reportMeasurement,
|
|
47
|
+
},
|
|
48
|
+
}, props.children)
|
|
49
|
+
end
|
|
50
|
+
local Grid = React.forwardRef(function(props, ref)
|
|
51
|
+
local theme = React.useContext(CleanThemeContext)
|
|
52
|
+
local width, setWidth = React.useState(0)
|
|
53
|
+
local heights, setHeights = React.useState({
|
|
54
|
+
key = "",
|
|
55
|
+
values = {},
|
|
56
|
+
})
|
|
57
|
+
local lock, setLock = React.useState(nil)
|
|
58
|
+
local breakpoints = props.breakpoints or theme.breakpoints
|
|
59
|
+
local breakpoint = BreakpointHelper:getBreakpoint(width, breakpoints)
|
|
60
|
+
local _condition = SizeHelper:resolveResponsiveValue(props.cols, breakpoint)
|
|
61
|
+
if _condition == nil then
|
|
62
|
+
_condition = 1
|
|
63
|
+
end
|
|
64
|
+
local cols = math.max(_condition, 1)
|
|
65
|
+
local gap = SpacingHelper:GetPadding(theme, props.gap)
|
|
66
|
+
local cellWidthScale = 1 / cols
|
|
67
|
+
local cellWidthOffset = math.floor(-gap * (cols - 1) / cols)
|
|
68
|
+
local cellWidth = UDim.new(cellWidthScale, cellWidthOffset)
|
|
69
|
+
local childCount = React.Children.count(props.children)
|
|
70
|
+
local measureKey = `{width}:{cols}:{gap}:{childCount}`
|
|
71
|
+
local locked = lock ~= nil and lock.key == measureKey
|
|
72
|
+
local lockedHeight = if locked then lock.height else 0
|
|
73
|
+
React.useEffect(function()
|
|
74
|
+
local _condition_1 = locked or heights.key ~= measureKey
|
|
75
|
+
if not _condition_1 then
|
|
76
|
+
-- ▼ ReadonlyMap.size ▼
|
|
77
|
+
local _size = 0
|
|
78
|
+
for _1 in heights.values do
|
|
79
|
+
_size += 1
|
|
80
|
+
end
|
|
81
|
+
-- ▲ ReadonlyMap.size ▲
|
|
82
|
+
_condition_1 = _size < childCount
|
|
83
|
+
end
|
|
84
|
+
if _condition_1 then
|
|
85
|
+
return nil
|
|
86
|
+
end
|
|
87
|
+
local cancelled = false
|
|
88
|
+
task.spawn(function()
|
|
89
|
+
task.wait()
|
|
90
|
+
task.wait()
|
|
91
|
+
if cancelled then
|
|
92
|
+
return nil
|
|
93
|
+
end
|
|
94
|
+
local max = 0
|
|
95
|
+
for _1, height in heights.values do
|
|
96
|
+
max = math.max(max, height)
|
|
97
|
+
end
|
|
98
|
+
setLock({
|
|
99
|
+
key = measureKey,
|
|
100
|
+
height = max,
|
|
101
|
+
})
|
|
102
|
+
end)
|
|
103
|
+
return function()
|
|
104
|
+
cancelled = true
|
|
105
|
+
end
|
|
106
|
+
end, { heights, locked, measureKey, childCount })
|
|
107
|
+
local reportHeight = React.useCallback(function(reportKey, index, height)
|
|
108
|
+
setHeights(function(current)
|
|
109
|
+
local values = if current.key == reportKey then current.values else {}
|
|
110
|
+
local updated = {}
|
|
111
|
+
for key, value in values do
|
|
112
|
+
updated[key] = value
|
|
113
|
+
end
|
|
114
|
+
local _index = index
|
|
115
|
+
local _height = height
|
|
116
|
+
updated[_index] = _height
|
|
117
|
+
return {
|
|
118
|
+
key = reportKey,
|
|
119
|
+
values = updated,
|
|
120
|
+
}
|
|
121
|
+
end)
|
|
122
|
+
end, {})
|
|
123
|
+
local cellIndex = 0
|
|
124
|
+
local _attributes = {}
|
|
125
|
+
local _condition_1 = props.name
|
|
126
|
+
if _condition_1 == nil then
|
|
127
|
+
_condition_1 = "Grid"
|
|
128
|
+
end
|
|
129
|
+
_attributes.key = _condition_1
|
|
130
|
+
_attributes.ref = ref
|
|
131
|
+
_attributes.Size = SizeHelper:GetSize(props, UDim2.fromScale(1, 1))
|
|
132
|
+
_attributes.AutomaticSize = Enum.AutomaticSize.Y
|
|
133
|
+
_attributes.BackgroundTransparency = 1
|
|
134
|
+
_attributes.Change = {
|
|
135
|
+
AbsoluteSize = function(instance)
|
|
136
|
+
local nextWidth = instance.AbsoluteSize.X
|
|
137
|
+
setWidth(function(currentWidth)
|
|
138
|
+
return if currentWidth == nextWidth then currentWidth else nextWidth
|
|
139
|
+
end)
|
|
140
|
+
end,
|
|
141
|
+
}
|
|
142
|
+
return React.createElement("frame", _attributes, if locked then (React.createElement("uigridlayout", {
|
|
143
|
+
key = "GridLayout",
|
|
144
|
+
CellSize = UDim2.new(cellWidthScale, cellWidthOffset, 0, lockedHeight),
|
|
145
|
+
CellPadding = UDim2.new(0, gap, 0, gap),
|
|
146
|
+
FillDirection = Enum.FillDirection.Horizontal,
|
|
147
|
+
FillDirectionMaxCells = cols,
|
|
148
|
+
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
149
|
+
})) else (React.createElement("uilistlayout", {
|
|
150
|
+
key = "GridMeasureLayout",
|
|
151
|
+
FillDirection = Enum.FillDirection.Horizontal,
|
|
152
|
+
Wraps = true,
|
|
153
|
+
Padding = UDim.new(0, gap),
|
|
154
|
+
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
155
|
+
})), React.Children.map(props.children, function(child)
|
|
156
|
+
local _original = cellIndex
|
|
157
|
+
cellIndex += 1
|
|
158
|
+
local index = _original
|
|
159
|
+
return React.createElement(GridCell, {
|
|
160
|
+
key = index,
|
|
161
|
+
index = index,
|
|
162
|
+
width = cellWidth,
|
|
163
|
+
height = lockedHeight,
|
|
164
|
+
locked = locked,
|
|
165
|
+
measureKey = measureKey,
|
|
166
|
+
onMeasured = reportHeight,
|
|
167
|
+
}, child)
|
|
168
|
+
end))
|
|
169
|
+
end)
|
|
170
|
+
return {
|
|
171
|
+
Grid = Grid,
|
|
172
|
+
}
|