@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.
Files changed (51) hide show
  1. package/out/Components/Chart/Pie.luau +0 -1
  2. package/out/Components/Decorator/Gradient.d.ts +8 -0
  3. package/out/Components/Decorator/Gradient.luau +23 -0
  4. package/out/Components/Decorator/index.d.ts +1 -0
  5. package/out/Components/Decorator/init.luau +3 -0
  6. package/out/Components/Input/Button.luau +5 -1
  7. package/out/Components/Input/Checkbox.luau +6 -2
  8. package/out/Components/Input/HoverButton.luau +0 -2
  9. package/out/Components/Input/Input.luau +8 -6
  10. package/out/Components/Input/Select.d.ts +2 -1
  11. package/out/Components/Input/Select.luau +10 -11
  12. package/out/Components/Input/Slider.luau +0 -24
  13. package/out/Components/Input/Switch.luau +0 -2
  14. package/out/Components/Interaction/Modal.luau +0 -14
  15. package/out/Components/Interaction/Tooltip.luau +0 -1
  16. package/out/Components/Layout/Container.d.ts +2 -0
  17. package/out/Components/Layout/Container.luau +4 -1
  18. package/out/Components/Layout/Grid.d.ts +10 -0
  19. package/out/Components/Layout/Grid.luau +172 -0
  20. package/out/Components/Layout/Group.luau +38 -33
  21. package/out/Components/Layout/Pagination.luau +0 -5
  22. package/out/Components/Layout/Tabs.d.ts +2 -1
  23. package/out/Components/Layout/Tabs.luau +12 -33
  24. package/out/Components/Layout/index.d.ts +1 -0
  25. package/out/Components/Layout/init.luau +3 -0
  26. package/out/Components/Surface/Box.d.ts +2 -1
  27. package/out/Components/Surface/Box.luau +3 -0
  28. package/out/Components/Surface/Card.luau +54 -111
  29. package/out/Components/Surface/ProgressBar.d.ts +14 -0
  30. package/out/Components/Surface/ProgressBar.luau +230 -0
  31. package/out/Components/Surface/index.d.ts +1 -0
  32. package/out/Components/Surface/init.luau +3 -0
  33. package/out/Components/Typography/Text.luau +0 -6
  34. package/out/Contexts/modal.context.luau +0 -3
  35. package/out/Helpers/color.helper.luau +28 -0
  36. package/out/Helpers/css.helper.d.ts +4 -1
  37. package/out/Helpers/css.helper.luau +76 -6
  38. package/out/Helpers/gui.helper.luau +0 -3
  39. package/out/Helpers/size.helper.luau +0 -2
  40. package/out/Helpers/spacing.helper.luau +0 -3
  41. package/out/Helpers/typography.helper.luau +0 -2
  42. package/out/Interfaces/css.types.d.ts +7 -0
  43. package/out/Interfaces/css.types.luau +0 -20
  44. package/out/Providers/registry.provider.luau +0 -2
  45. package/out/Theme/theme.style.d.ts +8 -1
  46. package/out/Theme/theme.template.d.ts +44 -2
  47. package/out/Theme/themes/dark.theme.luau +122 -0
  48. package/out/Theme/themes/default.theme.luau +80 -0
  49. package/out/Theme/themes/sandstone.theme.luau +70 -0
  50. package/out/Theme/themes/wooden.theme.luau +73 -0
  51. 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
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './BoxShadow';
2
2
  export * from './Corners';
3
+ export * from './Gradient';
3
4
  export * from './Padding';
@@ -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.button.intents).backgroundColor
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 _exp_2 = React.createElement(Padding, _attributes_1)
85
- local _exp_3 = props.icon ~= nil and (React.createElement(Icon, {
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
- }, _exp_3, React.createElement(FlexItem, nil, React.createElement("textbox", _attributes_2))))
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("uistroke", {
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 _exp_2 = React.createElement(Corners, {
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 _exp_3 = React.createElement(Padding, _attributes_1)
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 _exp_4 = React.createElement(HStack, nil, React.createElement(FlexItem, nil, React.createElement(Text, _attributes_2)), React.createElement(Icon, {
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
- }, _exp_1, _exp_2, _exp_3, _exp_4, _condition_5)))
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
@@ -212,7 +212,6 @@ local function Tooltip(props)
212
212
  return nil
213
213
  end
214
214
  task.delay(fadeDuration, function()
215
- -- Do not remove it if the tooltip was shown again.
216
215
  if hideRequest.current == request then
217
216
  setTarget(nil)
218
217
  end
@@ -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(Group.Element, {
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
+ }