@rbxts/react-clean-ui 1.2.2 → 1.2.4

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 +2 -103
  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 +2 -1
  46. package/out/Theme/theme.template.d.ts +41 -1
  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
@@ -1,27 +1,32 @@
1
1
  -- Compiled with roblox-ts v3.0.0
2
2
  local TS = _G[script]
3
3
  local React = TS.import(script, TS.getModule(script, "@rbxts", "react"))
4
- -- import { HttpService } from "@rbxts/services";
5
4
  local RegistryContext = TS.import(script, script.Parent.Parent.Parent, "Providers").RegistryContext
6
5
  local GroupContext = React.createContext(nil)
6
+ local nextFallbackElementId = 0
7
7
  local function GroupElement(props)
8
8
  local registry = React.useContext(RegistryContext)
9
9
  local context = React.useContext(GroupContext)
10
- local _result = registry
11
- if _result ~= nil then
12
- _result = _result.GetNextId()
13
- end
14
- local _condition = _result
15
- if _condition == nil then
16
- _condition = ""
10
+ local idRef = React.useRef()
11
+ if idRef.current == nil then
12
+ nextFallbackElementId += 1
13
+ local _result = registry
14
+ if _result ~= nil then
15
+ _result = _result.GetNextId()
16
+ end
17
+ local _condition = _result
18
+ if _condition == nil then
19
+ _condition = `group-element-{nextFallbackElementId}`
20
+ end
21
+ idRef.current = _condition
17
22
  end
18
- local id = React.useRef(_condition).current
23
+ local id = idRef.current
19
24
  local enabled = props.enabled == true and context ~= nil
20
25
  local _exp = function()
21
26
  if not enabled then
22
- local _result_1 = context
23
- if _result_1 ~= nil then
24
- _result_1.removeElement(id)
27
+ local _result = context
28
+ if _result ~= nil then
29
+ _result.removeElement(id)
25
30
  end
26
31
  return nil
27
32
  end
@@ -29,54 +34,54 @@ local function GroupElement(props)
29
34
  context.removeElement(id)
30
35
  end
31
36
  end
32
- local _result_1 = context
33
- if _result_1 ~= nil then
34
- _result_1 = _result_1.removeElement
37
+ local _result = context
38
+ if _result ~= nil then
39
+ _result = _result.removeElement
35
40
  end
36
- React.useEffect(_exp, { enabled, _result_1 })
41
+ React.useEffect(_exp, { enabled, _result })
37
42
  if not enabled then
38
43
  return props.children
39
44
  end
45
+ local _result_1 = props.padding
46
+ if _result_1 ~= nil then
47
+ _result_1 = _result_1.left
48
+ end
49
+ local _condition = _result_1
50
+ if _condition == nil then
51
+ _condition = 0
52
+ end
40
53
  local _result_2 = props.padding
41
54
  if _result_2 ~= nil then
42
- _result_2 = _result_2.left
55
+ _result_2 = _result_2.right
43
56
  end
44
57
  local _condition_1 = _result_2
45
58
  if _condition_1 == nil then
46
59
  _condition_1 = 0
47
60
  end
61
+ local horizontalPadding = _condition + _condition_1
48
62
  local _result_3 = props.padding
49
63
  if _result_3 ~= nil then
50
- _result_3 = _result_3.right
64
+ _result_3 = _result_3.top
51
65
  end
52
66
  local _condition_2 = _result_3
53
67
  if _condition_2 == nil then
54
68
  _condition_2 = 0
55
69
  end
56
- local horizontalPadding = _condition_1 + _condition_2
57
70
  local _result_4 = props.padding
58
71
  if _result_4 ~= nil then
59
- _result_4 = _result_4.top
72
+ _result_4 = _result_4.bottom
60
73
  end
61
74
  local _condition_3 = _result_4
62
75
  if _condition_3 == nil then
63
76
  _condition_3 = 0
64
77
  end
65
- local _result_5 = props.padding
66
- if _result_5 ~= nil then
67
- _result_5 = _result_5.bottom
68
- end
69
- local _condition_4 = _result_5
70
- if _condition_4 == nil then
71
- _condition_4 = 0
72
- end
73
- local verticalPadding = _condition_3 + _condition_4
78
+ local verticalPadding = _condition_2 + _condition_3
74
79
  local _attributes = {}
75
- local _condition_5 = props.name
76
- if _condition_5 == nil then
77
- _condition_5 = "GroupElement"
80
+ local _condition_4 = props.name
81
+ if _condition_4 == nil then
82
+ _condition_4 = "GroupElement"
78
83
  end
79
- _attributes.key = _condition_5
84
+ _attributes.key = _condition_4
80
85
  _attributes.BackgroundTransparency = 1
81
86
  _attributes.AutomaticSize = Enum.AutomaticSize.XY
82
87
  _attributes.Change = {
@@ -51,8 +51,6 @@ local function computePaginationItems(page, totalPages, siblingCount)
51
51
  local showLeftEllipsis = leftSiblingIndex > 2
52
52
  local showRightEllipsis = rightSiblingIndex < pageCount - 1
53
53
  if not showLeftEllipsis and showRightEllipsis then
54
- -- Near the start: no left ellipsis needed, so extend the leading run of
55
- -- numbers to keep the total item count constant.
56
54
  local leftItemCount = siblings * 2 + 3
57
55
  local items = {}
58
56
  do
@@ -76,8 +74,6 @@ local function computePaginationItems(page, totalPages, siblingCount)
76
74
  return items
77
75
  end
78
76
  if showLeftEllipsis and not showRightEllipsis then
79
- -- Near the end: no right ellipsis needed, so extend the trailing run of
80
- -- numbers to keep the total item count constant.
81
77
  local rightItemCount = siblings * 2 + 3
82
78
  local items = { 1, "ellipsis" }
83
79
  do
@@ -98,7 +94,6 @@ local function computePaginationItems(page, totalPages, siblingCount)
98
94
  end
99
95
  return items
100
96
  end
101
- -- Both ellipses shown (the normal middle case) — unchanged from before.
102
97
  local items = { 1, "ellipsis" }
103
98
  do
104
99
  local value = leftSiblingIndex
@@ -1,5 +1,5 @@
1
1
  import React from "@rbxts/react";
2
- import { PaddingProps, ScalableElementProps } from "../../Interfaces";
2
+ import { CssBackgroundGradient, PaddingProps, ScalableElementProps } from "../../Interfaces";
3
3
  import { CssBackgroundImage } from "../../Theme";
4
4
  interface TabTitleProps extends PaddingProps {
5
5
  value: string;
@@ -17,6 +17,7 @@ interface TabsListProps extends ScalableElementProps {
17
17
  declare const TabsList: React.ForwardRefExoticComponent<TabsListProps & React.RefAttributes<ImageLabel>>;
18
18
  interface TabsBodyProps extends ScalableElementProps {
19
19
  backgroundImage?: CssBackgroundImage;
20
+ backgroundGradient?: CssBackgroundGradient;
20
21
  children?: React.ReactNode;
21
22
  }
22
23
  declare const TabsBody: React.ForwardRefExoticComponent<TabsBodyProps & React.RefAttributes<ImageLabel>>;
@@ -9,6 +9,7 @@ local CleanThemeContext = TS.import(script, script.Parent.Parent.Parent, "Contex
9
9
  local _Decorator = TS.import(script, script.Parent.Parent, "Decorator")
10
10
  local BoxShadow = _Decorator.BoxShadow
11
11
  local Corners = _Decorator.Corners
12
+ local Gradient = _Decorator.Gradient
12
13
  local Padding = _Decorator.Padding
13
14
  local _Helpers = TS.import(script, script.Parent.Parent.Parent, "Helpers")
14
15
  local ColorHelper = _Helpers.ColorHelper
@@ -18,10 +19,6 @@ local TypographyHelper = _Helpers.TypographyHelper
18
19
  local _HoverButton = TS.import(script, script.Parent.Parent, "Input", "HoverButton")
19
20
  local HoverButton = _HoverButton.HoverButton
20
21
  local HoverButtonContext = _HoverButton.HoverButtonContext
21
- -- Selection only — Tabs.List/Tabs.Body/Tabs.Title/Tabs.Content each render
22
- -- themselves for real (see Card.tsx's CardHeader/CardFooter for the same
23
- -- "Root provides Context, subparts consume it independently" pattern), so
24
- -- there's nothing here to scan or harvest from children.
25
22
  local TabsContext = React.createContext({
26
23
  selected = nil,
27
24
  setSelected = function() end,
@@ -57,23 +54,20 @@ local function TabButtonContent(props)
57
54
  typography = TypographyHelper:getTypography(theme, nil, intent.typography),
58
55
  }))
59
56
  end
60
- -- The real per-tab button — derives its own default/hover/focus color scheme
61
- -- from the theme (same per-instance derivation Card.Header/Card.Footer use,
62
- -- not hoisted to Root) and drives selection itself via TabsContext.
63
57
  local function TabTitle(props)
64
58
  local theme = React.useContext(CleanThemeContext)
65
59
  local _binding = React.useContext(TabsContext)
66
60
  local selected = _binding.selected
67
61
  local setSelected = _binding.setSelected
68
62
  local isSelected = selected == props.value
69
- -- The first-mounted Tabs.Title claims the selection if none is set yet,
70
- -- preserving "first tab selected by default" now that nothing scans the
71
- -- tab list up front. Known limitation: if the currently-selected tab's
72
- -- Tabs.Title unmounts, selection isn't automatically reassigned.
73
63
  React.useEffect(function()
74
- if selected == nil then
75
- setSelected(props.value)
76
- end
64
+ setSelected(function(current)
65
+ local _condition = current
66
+ if _condition == nil then
67
+ _condition = props.value
68
+ end
69
+ return _condition
70
+ end)
77
71
  end, {})
78
72
  local buttonDefault = ColorHelper:getIntentColors(theme, "primary", "default", theme.components.tabs.button.intents)
79
73
  local buttonHover = ColorHelper:getIntentColors(theme, "primary", "hover", theme.components.tabs.button.intents)
@@ -130,14 +124,6 @@ local function TabTitle(props)
130
124
  },
131
125
  }, React.createElement(TabButtonContent, _attributes))
132
126
  end
133
- -- Always mounted — visibility is toggled rather than the panel being
134
- -- unmounted/remounted, so per-tab local state (e.g. a Scroller's scroll
135
- -- position) survives switching tabs. Roblox excludes a GuiObject with
136
- -- Visible=false from its ancestors' AutomaticSize/UIListLayout
137
- -- content-size calculations, so the hidden panels don't inflate Tabs.Body's
138
- -- own AutomaticSize; since only one panel is ever visible at a time, the
139
- -- default (unset) Position/AnchorPoint every panel shares never causes a
140
- -- visible overlap either.
141
127
  local function TabContent(props)
142
128
  local _binding = React.useContext(TabsContext)
143
129
  local selected = _binding.selected
@@ -163,6 +149,8 @@ local TabsList = React.forwardRef(function(props, ref)
163
149
  _attributes.backgroundImage = theme.components.tabs.list.backgroundImage
164
150
  return React.createElement(Container, _attributes, React.createElement(Corners, {
165
151
  radius = theme.components.tabs.list.cornerRadius,
152
+ }), React.createElement(Gradient, {
153
+ value = theme.components.tabs.list.backgroundGradient,
166
154
  }), React.createElement(Padding, {
167
155
  resolvedPadding = SpacingHelper:GetResolvedPadding(theme, {}, theme.components.tabs.list.spacing, theme.components.tabs.list.padding),
168
156
  }), React.createElement(HStack, nil, props.children))
@@ -183,19 +171,10 @@ local TabsBody = React.forwardRef(function(props, ref)
183
171
  resolvedPadding = SpacingHelper:GetResolvedPadding(theme, {}, theme.components.tabs.spacing, theme.components.tabs.padding),
184
172
  }), React.createElement(Corners, {
185
173
  radius = theme.components.tabs.cornerRadius,
174
+ }), React.createElement(Gradient, {
175
+ value = props.backgroundGradient or theme.components.tabs.backgroundGradient,
186
176
  }), props.children)
187
177
  end)
188
- -- Root doesn't render a real Roblox Instance of its own (just a Context
189
- -- Provider around a VStack, itself just a Fragment) — see Group.tsx for the
190
- -- same shape. It's still wrapped in React.forwardRef, not a plain function,
191
- -- because roblox-ts compiles a bare arrow function to an actual Lua
192
- -- `function` value, and Lua functions can't have table-style properties
193
- -- (Tabs.List = ...) assigned onto them — forwardRef's return value compiles
194
- -- to a table instead. The ref itself is genuinely unused: there's no
195
- -- sensible Instance for it to point at, so RefAttributes<Frame> below is a
196
- -- type-level placeholder to keep this consistent with every other compound
197
- -- component's shape, not a real forwarded ref — Tabs does not support a
198
- -- `ref` prop in practice.
199
178
  local Tabs = React.forwardRef(function(props, _ref)
200
179
  local selected, setSelected = React.useState(props.defaultValue)
201
180
  local contextValue = React.useMemo(function()
@@ -5,6 +5,7 @@ export * from './Draggable';
5
5
  export * from './Droppable';
6
6
  export * from './Fieldset';
7
7
  export * from './FlexItem';
8
+ export * from './Grid';
8
9
  export * from './Group';
9
10
  export * from './HStack';
10
11
  export * from './Pagination';
@@ -22,6 +22,9 @@ end
22
22
  for _k, _v in TS.import(script, script, "FlexItem") or {} do
23
23
  exports[_k] = _v
24
24
  end
25
+ for _k, _v in TS.import(script, script, "Grid") or {} do
26
+ exports[_k] = _v
27
+ end
25
28
  for _k, _v in TS.import(script, script, "Group") or {} do
26
29
  exports[_k] = _v
27
30
  end
@@ -1,10 +1,11 @@
1
1
  import React from "@rbxts/react";
2
- import { BackgroundElementProps, PositionElementProps, ShadowElementProps, SizeElementProps, SpacedElementProps, ZIndexElementProps } from "../../Interfaces/";
2
+ import { BackgroundElementProps, CssBackgroundGradient, PositionElementProps, ShadowElementProps, SizeElementProps, SpacedElementProps, ZIndexElementProps } from "../../Interfaces/";
3
3
  import { CssBackgroundImage } from "../../Theme";
4
4
  export interface BoxProps extends SpacedElementProps, ShadowElementProps, BackgroundElementProps, ZIndexElementProps, SizeElementProps, PositionElementProps, React.InstanceProps<ImageLabel> {
5
5
  'border-thickness'?: number;
6
6
  'border-color'?: Color3;
7
7
  'background-image'?: CssBackgroundImage;
8
+ 'background-gradient'?: CssBackgroundGradient;
8
9
  name?: string;
9
10
  }
10
11
  export declare const Box: React.ForwardRefExoticComponent<Omit<BoxProps, "ref"> & React.RefAttributes<ImageLabel>>;
@@ -6,6 +6,7 @@ local _Decorator = TS.import(script, script.Parent.Parent, "Decorator")
6
6
  local Padding = _Decorator.Padding
7
7
  local Corners = _Decorator.Corners
8
8
  local BoxShadow = _Decorator.BoxShadow
9
+ local Gradient = _Decorator.Gradient
9
10
  local Container = TS.import(script, script.Parent.Parent, "Layout").Container
10
11
  local _Helpers = TS.import(script, script.Parent.Parent.Parent, "Helpers")
11
12
  local SizeHelper = _Helpers.SizeHelper
@@ -54,6 +55,8 @@ local Box = React.forwardRef(function(props, ref)
54
55
  resolvedPadding = SpacingHelper:GetResolvedPadding(theme, props, theme.components.box.spacing, theme.components.box.padding),
55
56
  }), React.createElement(Corners, {
56
57
  radius = theme.components.box.cornerRadius,
58
+ }), React.createElement(Gradient, {
59
+ value = props["background-gradient"] or theme.components.box.backgroundGradient,
57
60
  }), props.children)
58
61
  end)
59
62
  return {
@@ -14,13 +14,6 @@ local SpacingHelper = _Helpers.SpacingHelper
14
14
  local CleanThemeContext = TS.import(script, script.Parent.Parent.Parent, "Contexts").CleanThemeContext
15
15
  local Padding = TS.import(script, script.Parent.Parent, "Decorator").Padding
16
16
  local CardContext = React.createContext({})
17
- -- Resolves a theme-driven CssPosition into raw Position/AnchorPoint offsets.
18
- -- This is a one-off resolver rather than a SizeHelper addition because
19
- -- CssPosition's `center` is axis-aware (`"x"` / `"y"`) so it can express
20
- -- "center horizontally, anchor to the top with an offset" — something
21
- -- SizeHelper.GetPosition/GetAnchor can't do since they apply `center`
22
- -- identically to both axes, and that symmetric behavior is relied on
23
- -- elsewhere in the codebase so isn't something to widen here.
24
17
  local function resolveCssPositionOffset(position)
25
18
  local centerX = position.center == true or position.center == "x"
26
19
  local centerY = position.center == true or position.center == "y"
@@ -28,19 +21,6 @@ local function resolveCssPositionOffset(position)
28
21
  local anchorY = if centerY then 0.5 else (if position.top == nil and position.bottom ~= nil then 1 else 0)
29
22
  local posX = if centerX then UDim.new(0.5, 0) elseif position.left ~= nil then SizeHelper:toUDim(position.left) elseif position.right ~= nil then UDim.new(1 - SizeHelper:toUDim(position.right).Scale, -SizeHelper:toUDim(position.right).Offset) else UDim.new(0, 0)
30
23
  local posY = if centerY then UDim.new(0.5, 0) elseif position.top ~= nil then SizeHelper:toUDim(position.top) elseif position.bottom ~= nil then UDim.new(1 - SizeHelper:toUDim(position.bottom).Scale, -SizeHelper:toUDim(position.bottom).Offset) else UDim.new(0, 0)
31
- -- A theme-driven fixed/relative width (only meaningful in overlay mode,
32
- -- see CssPosition.width) forces a fixed-width/auto-height Size, taking
33
- -- over the caller's default Size={fromScale(0,0)}/AutomaticSize={XY} —
34
- -- otherwise Size/AutomaticSize are left undefined so the caller's own
35
- -- default applies unchanged. Parsed via CssHelper.parseCssSize (not
36
- -- SizeHelper.toUDim, used for top/left/right/bottom above) since it's
37
- -- the one that understands the "<percent>% - <px>px" calc() shape a
38
- -- width value may use (e.g. "100% - 50px").
39
- --
40
- -- When `width` isn't explicit but both `left` and `right` are set, imply
41
- -- a width from them the same way CSS does for an absolutely-positioned
42
- -- element: width = 100% - left - right. Explicit `width` always wins if
43
- -- somehow both are set.
44
24
  local impliedWidth = if position.width == nil and position.left ~= nil and position.right ~= nil then (function()
45
25
  local leftUDim = SizeHelper:toUDim(position.left)
46
26
  local rightUDim = SizeHelper:toUDim(position.right)
@@ -63,18 +43,6 @@ local function resolveCssPositionOffset(position)
63
43
  end
64
44
  return _object
65
45
  end
66
- -- Header/footer overlay mode escapes the card's VStack (a UIListLayout
67
- -- forcibly repositions every sibling it lays out, so there's no way to keep
68
- -- a custom Position/AnchorPoint on a child that stays inside it) — Card
69
- -- pulls an overlay-requesting Header/Footer out of the flow and renders it
70
- -- as an absolutely-positioned sibling of the Box instead. Overlay mode is
71
- -- requested via the instance `overlay` prop or `theme.components.card.header
72
- -- /footer.position.position === "absolute"`; when the instance sets any of
73
- -- its own Position/AnchorPoint/top/left/right/bottom/center fields, those
74
- -- win wholesale over the theme's CssPosition (mixing partial fields across
75
- -- the two differently-shaped position vocabularies isn't attempted), exactly
76
- -- mirroring the precedence the previous PositionElementProps-based
77
- -- implementation gave instance props.
78
46
  local function resolveOverlayPosition(props, themePosition)
79
47
  local _condition = props.overlay
80
48
  if _condition == nil then
@@ -180,6 +148,7 @@ local CardHeader = React.forwardRef(function(props, ref)
180
148
  _attributes.BackgroundColor3 = intent.backgroundColor
181
149
  _attributes.BorderSizePixel = 0
182
150
  _attributes.backgroundImage = intent.backgroundImage
151
+ _attributes.backgroundGradient = intent.backgroundGradient
183
152
  _attributes.Change = if overlay and card.reportOverlayHeaderRect ~= nil then {
184
153
  AbsolutePosition = function(instance)
185
154
  return card.reportOverlayHeaderRect(instance.AbsolutePosition, instance.AbsoluteSize)
@@ -211,14 +180,6 @@ local CardHeader = React.forwardRef(function(props, ref)
211
180
  end)
212
181
  local CardBody = React.forwardRef(function(props, ref)
213
182
  local theme = React.useContext(CleanThemeContext)
214
- -- Unified 4-tier padding resolution (see SpacingHelper.GetResolvedPadding):
215
- -- `card.body.spacing` (tier 2) overrides the global spacing map per
216
- -- scale key, falling back to it for any key it doesn't define, and
217
- -- `card.body.padding` (tier 3) overrides the scale-based tiers
218
- -- entirely at the active key. CardBody wraps its children in a
219
- -- Container, not a Box, so it doesn't get Box's automatic
220
- -- `box.padding` application for free — this resolves independently
221
- -- against `theme.components.card.body`'s own tiers.
222
183
  local paddingSourceProps = props
223
184
  local _attributes = {
224
185
  name = "CardBody",
@@ -266,6 +227,7 @@ local CardFooter = React.forwardRef(function(props, ref)
266
227
  _attributes.BackgroundColor3 = intent.backgroundColor
267
228
  _attributes.BorderSizePixel = 0
268
229
  _attributes.backgroundImage = intent.backgroundImage
230
+ _attributes.backgroundGradient = intent.backgroundGradient
269
231
  _attributes.Change = if overlay and card.reportOverlayFooterRect ~= nil then {
270
232
  AbsolutePosition = function(instance)
271
233
  return card.reportOverlayFooterRect(instance.AbsolutePosition, instance.AbsoluteSize)
@@ -297,18 +259,6 @@ local CardFooter = React.forwardRef(function(props, ref)
297
259
  end)
298
260
  local Card = React.forwardRef(function(props, ref)
299
261
  local theme = React.useContext(CleanThemeContext)
300
- -- Overlay clearance: an overlay header (see resolveOverlayPosition)
301
- -- is pulled out of the VStack entirely, so nothing reserves space
302
- -- for it — its rendered box typically extends downward past its own
303
- -- anchor point and overlaps into the top of the Box. These two
304
- -- pieces of state capture the header's reported rect (via
305
- -- CardContext.reportOverlayHeaderRect, set on CardHeader below) and
306
- -- the overlay wrapper frame's own AbsolutePosition, so the amount of
307
- -- that overlap can be measured and reserved as extra top padding on
308
- -- the Box (see headerClearance/boxProps below). Both are undefined
309
- -- until their first Change event fires after mount, which is the
310
- -- same measure-then-settle characteristic Accordion.tsx accepts for
311
- -- its own AbsoluteSize-driven measurements.
312
262
  local headerRect, setHeaderRect = React.useState()
313
263
  local footerRect, setFooterRect = React.useState()
314
264
  local wrapperAbsoluteY, setWrapperAbsoluteY = React.useState()
@@ -334,10 +284,6 @@ local Card = React.forwardRef(function(props, ref)
334
284
  }
335
285
  end, { props.intent, reportOverlayHeaderRect, reportOverlayFooterRect })
336
286
  local intent = ColorHelper:getIntentColors(theme, props.intent or "primary", "default", theme.components.card.header.intents)
337
- -- Pull out a Header/Footer that wants overlay placement so it can be
338
- -- rendered outside the VStack below (see resolveOverlayPosition above
339
- -- for why it can't stay inside the VStack and still be positioned).
340
- -- Everything else renders in place, in its original order.
341
287
  local _binding = React.useMemo(function()
342
288
  local flow = {}
343
289
  local header
@@ -392,21 +338,9 @@ local Card = React.forwardRef(function(props, ref)
392
338
  local overlayHeader = _binding.overlayHeader
393
339
  local overlayFooter = _binding.overlayFooter
394
340
  local hasOverlay = overlayHeader ~= nil or overlayFooter ~= nil
395
- -- How far the overlay header's bottom edge extends past the
396
- -- wrapper's (i.e. the Box's) top edge — 0 when there's no overlap
397
- -- (e.g. a small/no theme offset) or nothing has been measured yet.
398
341
  local headerClearance = if overlayHeader ~= nil and headerRect ~= nil and wrapperAbsoluteY ~= nil then math.max(0, (headerRect.position.Y + headerRect.size.Y) - wrapperAbsoluteY) else 0
399
- -- Same idea, mirrored for the footer: the wrapper's bottom edge
400
- -- (its top plus its own height) minus the footer's reported top
401
- -- edge (AbsolutePosition is always the top-left corner regardless
402
- -- of AnchorPoint) is how far the footer's top edge sits above the
403
- -- Box's bottom edge, i.e. how much it overlaps upward into it.
404
342
  local wrapperBottomY = if wrapperAbsoluteY ~= nil and wrapperAbsoluteSize ~= nil then wrapperAbsoluteY + wrapperAbsoluteSize.Y else nil
405
343
  local footerClearance = if overlayFooter ~= nil and footerRect ~= nil and wrapperBottomY ~= nil then math.max(0, wrapperBottomY - footerRect.position.Y) else 0
406
- -- The Box below now sits inside an extra positioning frame (see
407
- -- boxWithOverlay), so its own Position/AnchorPoint/ZIndex/LayoutOrder
408
- -- are cleared here to avoid double-applying them — the wrapper frame
409
- -- owns those instead.
410
344
  local _result
411
345
  if hasOverlay then
412
346
  local _object = table.clone(props)
@@ -424,18 +358,6 @@ local Card = React.forwardRef(function(props, ref)
424
358
  _result = props
425
359
  end
426
360
  local boxProps = _result
427
- -- When there's no footer at all, footerClearance is always 0 (there's
428
- -- nothing to measure an overlap against), so fall back to the Box's
429
- -- own explicit theme.components.box.padding bottom inset — if the
430
- -- theme sets one — as a floor instead. This keeps content clear of a
431
- -- themed Box's decorative border image (e.g. wooden's wood-frame art,
432
- -- which needs a real bottom inset) even when there's no footer to
433
- -- reserve that space via measured overlap. Themes that don't set an
434
- -- explicit box padding (GetExplicitPadding returns undefined) resolve
435
- -- this floor to 0, so behavior there is unchanged. When a footer IS
436
- -- present, footerClearance (its real measured overlap) is used as-is
437
- -- exactly as before — this floor never applies then, since the
438
- -- footer's own overlap already reserves whatever space it needs.
439
361
  local _result_1
440
362
  if overlayFooter == nil then
441
363
  local _result_2 = SpacingHelper:GetExplicitPadding(theme.components.box.padding, theme.default.spacing)
@@ -451,12 +373,6 @@ local Card = React.forwardRef(function(props, ref)
451
373
  _result_1 = 0
452
374
  end
453
375
  local explicitBoxBottomFloor = _result_1
454
- -- When an overlay header and/or footer measurably overlaps into the
455
- -- Box (headerClearance/footerClearance > 0), or the footer-absent
456
- -- floor above is nonzero, reserve that much extra top/bottom padding
457
- -- via resolvedPadding — this takes over Box's own outer padding,
458
- -- which is otherwise 0/0/0/0 since Card always forces spacing="None"
459
- -- on Box below.
460
376
  local _result_2
461
377
  if headerClearance > 0 or footerClearance > 0 or explicitBoxBottomFloor > 0 then
462
378
  local _object = table.clone(boxProps)
@@ -486,23 +402,6 @@ local Card = React.forwardRef(function(props, ref)
486
402
  local cardBox = (React.createElement(Box, _attributes, React.createElement(VStack, {
487
403
  spacing = "None",
488
404
  }, flowChildren)))
489
- -- ClipsDescendants is off so an overlay header/footer can protrude
490
- -- past the Box's own edges (e.g. a plaque mounted above the top
491
- -- border). This frame takes over the Position/AnchorPoint the Box
492
- -- would otherwise have used, and auto-sizes to hug the Box (plus
493
- -- whatever the overlay siblings protrude by).
494
- --
495
- -- `center` is stripped before deriving Position/AnchorPoint here,
496
- -- the same way `cardBox`'s Box always gets `center={undefined}`:
497
- -- when `center` is set, centering is handled by the outer
498
- -- `isCentered` wrapper below (a UIListLayout that centers this
499
- -- whole frame), not by this frame's own Position/AnchorPoint. If
500
- -- both applied `center` at once, the UIListLayout would place the
501
- -- frame using an (0,0)-anchor assumption while the frame itself
502
- -- reported a (0.5,0.5) AnchorPoint, offsetting it by half its own
503
- -- size and letting its (ClipsDescendants=false) contents spill out.
504
- -- Explicit top/left/right/bottom/Position/AnchorPoint overrides are
505
- -- unaffected and still apply directly to this frame.
506
405
  local _object = table.clone(props)
507
406
  setmetatable(_object, nil)
508
407
  _object.center = nil
@@ -0,0 +1,14 @@
1
+ import React from "@rbxts/react";
2
+ import { IntentElementProps, PositionElementProps, ScalableElementProps, SizeElementProps, ZIndexElementProps } from "../../Interfaces";
3
+ export interface ProgressBarProps extends IntentElementProps, ScalableElementProps, SizeElementProps, PositionElementProps, ZIndexElementProps, React.InstanceProps<ImageLabel> {
4
+ value: number;
5
+ max?: number;
6
+ label?: string;
7
+ showValue?: boolean;
8
+ valueFormatter?: (value: number, max: number) => string;
9
+ name?: string;
10
+ striped?: boolean;
11
+ stripeDuration?: number;
12
+ stripeDirection?: number;
13
+ }
14
+ export declare const ProgressBar: React.ForwardRefExoticComponent<Omit<ProgressBarProps, "ref"> & React.RefAttributes<ImageLabel>>;