@rbxts/react-clean-ui 1.0.36 → 1.0.38
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/Input/Button.d.ts +9 -0
- package/out/Components/Input/Button.luau +155 -46
- package/out/Components/Input/Checkbox.luau +21 -5
- package/out/Components/Input/Increment.d.ts +11 -0
- package/out/Components/Input/Increment.luau +107 -0
- package/out/Components/Input/Increment.step.d.ts +1 -0
- package/out/Components/Input/Increment.step.luau +25 -0
- package/out/Components/Input/Input.d.ts +4 -3
- package/out/Components/Input/Input.luau +124 -17
- package/out/Components/Input/Input.validation.d.ts +3 -0
- package/out/Components/Input/Input.validation.luau +21 -0
- package/out/Components/Input/Select.d.ts +4 -3
- package/out/Components/Input/Select.luau +23 -18
- package/out/Components/Input/Slider.d.ts +1 -1
- package/out/Components/Input/Slider.luau +68 -34
- package/out/Components/Input/index.d.ts +1 -0
- package/out/Components/Input/init.luau +3 -0
- package/out/Components/Layout/Accordion.d.ts +1 -1
- package/out/Components/Layout/Accordion.luau +7 -6
- package/out/Components/Layout/Container.d.ts +4 -2
- package/out/Components/Layout/Container.luau +12 -3
- package/out/Components/Layout/Draggable.luau +1 -1
- package/out/Components/Layout/Fieldset.d.ts +1 -1
- package/out/Components/Layout/FlexItem.d.ts +2 -1
- package/out/Components/Layout/FlexItem.luau +1 -0
- package/out/Components/Layout/Scroller.d.ts +1 -0
- package/out/Components/Layout/Scroller.luau +1 -1
- package/out/Components/Layout/Tabs.d.ts +1 -1
- package/out/Components/Layout/Tabs.luau +37 -7
- package/out/Components/Navigation/Menu.d.ts +1 -1
- package/out/Components/Surface/Box.d.ts +4 -2
- package/out/Components/Surface/Box.luau +12 -3
- package/out/Components/Surface/Card.d.ts +8 -6
- package/out/Components/Surface/Card.luau +416 -24
- package/out/Components/Surface/Icon.luau +42 -4
- package/out/Components/Typography/Text.d.ts +1 -0
- package/out/Components/Typography/Text.luau +119 -10
- package/out/Contexts/row.context.d.ts +1 -1
- package/out/Contexts/theme.context.d.ts +2 -2
- package/out/Helpers/color.helper.d.ts +5 -3
- package/out/Helpers/color.helper.luau +62 -34
- package/out/Helpers/create-ui-story.d.ts +2 -2
- package/out/Helpers/create-ui-story.luau +33 -1
- package/out/Helpers/css.helper.d.ts +28 -2
- package/out/Helpers/css.helper.luau +208 -0
- package/out/Helpers/index.d.ts +1 -0
- package/out/Helpers/init.luau +3 -0
- package/out/Helpers/size.helper.d.ts +3 -1
- package/out/Helpers/size.helper.luau +10 -9
- package/out/Helpers/spacing.helper.d.ts +3 -3
- package/out/Helpers/typography.helper.d.ts +2 -2
- package/out/Interfaces/css.types.d.ts +28 -0
- package/out/Interfaces/css.types.luau +17 -0
- package/out/Interfaces/element.props.d.ts +61 -0
- package/out/Interfaces/element.props.luau +1 -0
- package/out/Interfaces/index.d.ts +4 -2
- package/out/Interfaces/init.luau +9 -3
- package/out/Interfaces/responsive.types.d.ts +26 -0
- package/out/Interfaces/semantics.d.ts +3 -0
- package/out/Interfaces/semantics.luau +2 -0
- package/out/Providers/app.provider.d.ts +2 -2
- package/out/Providers/theme.provider.d.ts +2 -2
- package/out/Theme/index.d.ts +1 -0
- package/out/Theme/theme.factory.d.ts +3 -3
- package/out/Theme/theme.style.d.ts +48 -0
- package/out/Theme/theme.style.luau +1 -0
- package/out/Theme/theme.template.d.ts +23 -26
- package/out/Theme/themes/dark.theme.d.ts +1 -1
- package/out/Theme/themes/dark.theme.luau +28 -0
- package/out/Theme/themes/default.theme.d.ts +2 -2
- package/out/Theme/themes/default.theme.luau +11 -1
- package/out/Theme/themes/index.d.ts +1 -0
- package/out/Theme/themes/init.luau +3 -0
- package/out/Theme/themes/sandstone.theme.d.ts +1 -1
- package/out/Theme/themes/sandstone.theme.luau +25 -0
- package/out/Theme/themes/wooden.theme.d.ts +1 -0
- package/out/Theme/themes/wooden.theme.luau +443 -0
- package/out/index.d.ts +8 -8
- package/package.json +18 -6
- package/out/Interfaces/clean.element.props.d.ts +0 -114
- /package/out/{Interfaces/userinput.d.ts → Helpers/input.helper.d.ts} +0 -0
- /package/out/{Interfaces/userinput.luau → Helpers/input.helper.luau} +0 -0
- /package/out/Interfaces/{clean.element.props.luau → responsive.types.luau} +0 -0
|
@@ -14,30 +14,191 @@ 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
|
+
local function resolveCssPositionOffset(position)
|
|
25
|
+
local centerX = position.center == true or position.center == "x"
|
|
26
|
+
local centerY = position.center == true or position.center == "y"
|
|
27
|
+
local anchorX = if centerX then 0.5 else (if position.left == nil and position.right ~= nil then 1 else 0)
|
|
28
|
+
local anchorY = if centerY then 0.5 else (if position.top == nil and position.bottom ~= nil then 1 else 0)
|
|
29
|
+
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
|
+
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
|
+
local impliedWidth = if position.width == nil and position.left ~= nil and position.right ~= nil then (function()
|
|
45
|
+
local leftUDim = SizeHelper:toUDim(position.left)
|
|
46
|
+
local rightUDim = SizeHelper:toUDim(position.right)
|
|
47
|
+
return UDim.new(1 - leftUDim.Scale - rightUDim.Scale, -leftUDim.Offset - rightUDim.Offset)
|
|
48
|
+
end)() else nil
|
|
49
|
+
local sizeOverride = if position.width ~= nil then {
|
|
50
|
+
Size = UDim2.new(CssHelper:parseCssSize(position.width), UDim.new(0, 0)),
|
|
51
|
+
AutomaticSize = Enum.AutomaticSize.Y,
|
|
52
|
+
} elseif impliedWidth ~= nil then {
|
|
53
|
+
Size = UDim2.new(impliedWidth, UDim.new(0, 0)),
|
|
54
|
+
AutomaticSize = Enum.AutomaticSize.Y,
|
|
55
|
+
} else {}
|
|
56
|
+
local _object = {
|
|
57
|
+
Position = UDim2.new(posX, posY),
|
|
58
|
+
AnchorPoint = Vector2.new(anchorX, anchorY),
|
|
59
|
+
ZIndex = position.zIndex,
|
|
60
|
+
}
|
|
61
|
+
for _k, _v in sizeOverride do
|
|
62
|
+
_object[_k] = _v
|
|
63
|
+
end
|
|
64
|
+
return _object
|
|
65
|
+
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
|
+
local function resolveOverlayPosition(props, themePosition)
|
|
79
|
+
local _condition = props.overlay
|
|
80
|
+
if _condition == nil then
|
|
81
|
+
local _result = themePosition
|
|
82
|
+
if _result ~= nil then
|
|
83
|
+
_result = _result.position
|
|
84
|
+
end
|
|
85
|
+
_condition = (_result == "absolute")
|
|
86
|
+
end
|
|
87
|
+
local overlay = _condition
|
|
88
|
+
if not overlay then
|
|
89
|
+
return {
|
|
90
|
+
overlay = overlay,
|
|
91
|
+
positionProps = {},
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
local hasInstancePosition = props.Position ~= nil or props.AnchorPoint ~= nil or props.top ~= nil or props.left ~= nil or props.right ~= nil or props.bottom ~= nil or props.center ~= nil
|
|
95
|
+
if hasInstancePosition then
|
|
96
|
+
local _object = {
|
|
97
|
+
overlay = overlay,
|
|
98
|
+
}
|
|
99
|
+
local _left = "positionProps"
|
|
100
|
+
local _object_1 = {
|
|
101
|
+
Position = SizeHelper:GetPosition(props),
|
|
102
|
+
AnchorPoint = SizeHelper:GetAnchor(props),
|
|
103
|
+
}
|
|
104
|
+
local _left_1 = "ZIndex"
|
|
105
|
+
local _condition_1 = props.ZIndex
|
|
106
|
+
if _condition_1 == nil then
|
|
107
|
+
local _result = themePosition
|
|
108
|
+
if _result ~= nil then
|
|
109
|
+
_result = _result.zIndex
|
|
110
|
+
end
|
|
111
|
+
_condition_1 = _result
|
|
112
|
+
if _condition_1 == nil then
|
|
113
|
+
_condition_1 = 2
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
_object_1[_left_1] = _condition_1
|
|
117
|
+
_object[_left] = _object_1
|
|
118
|
+
return _object
|
|
119
|
+
end
|
|
120
|
+
if themePosition ~= nil then
|
|
121
|
+
local resolved = resolveCssPositionOffset(themePosition)
|
|
122
|
+
local _object = {
|
|
123
|
+
overlay = overlay,
|
|
124
|
+
}
|
|
125
|
+
local _left = "positionProps"
|
|
126
|
+
local _object_1 = {
|
|
127
|
+
Position = resolved.Position,
|
|
128
|
+
AnchorPoint = resolved.AnchorPoint,
|
|
129
|
+
}
|
|
130
|
+
local _left_1 = "ZIndex"
|
|
131
|
+
local _condition_1 = props.ZIndex
|
|
132
|
+
if _condition_1 == nil then
|
|
133
|
+
_condition_1 = resolved.ZIndex
|
|
134
|
+
if _condition_1 == nil then
|
|
135
|
+
_condition_1 = 2
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
_object_1[_left_1] = _condition_1
|
|
139
|
+
_object_1.Size = resolved.Size
|
|
140
|
+
_object_1.AutomaticSize = resolved.AutomaticSize
|
|
141
|
+
_object[_left] = _object_1
|
|
142
|
+
return _object
|
|
143
|
+
end
|
|
144
|
+
local _object = {
|
|
145
|
+
overlay = overlay,
|
|
146
|
+
}
|
|
147
|
+
local _left = "positionProps"
|
|
148
|
+
local _object_1 = {}
|
|
149
|
+
local _left_1 = "ZIndex"
|
|
150
|
+
local _condition_1 = props.ZIndex
|
|
151
|
+
if _condition_1 == nil then
|
|
152
|
+
_condition_1 = 2
|
|
153
|
+
end
|
|
154
|
+
_object_1[_left_1] = _condition_1
|
|
155
|
+
_object[_left] = _object_1
|
|
156
|
+
return _object
|
|
157
|
+
end
|
|
17
158
|
local CardHeader = React.forwardRef(function(props, ref)
|
|
18
159
|
local theme = React.useContext(CleanThemeContext)
|
|
19
160
|
local card = React.useContext(CardContext)
|
|
20
161
|
local intent = ColorHelper:getIntentColors(theme, props.intent or card.intent or "primary", "default", theme.components.card.header.intents)
|
|
21
162
|
local padding = SpacingHelper:ResolveNumberPadding(SpacingHelper:GetPadding(theme, "md", theme.components.card.header.spacing))
|
|
22
163
|
local corners = CssHelper:parseCssSize(theme.components.card.cornerRadius)
|
|
164
|
+
local _binding = resolveOverlayPosition(props, theme.components.card.header.position)
|
|
165
|
+
local overlay = _binding.overlay
|
|
166
|
+
local positionProps = _binding.positionProps
|
|
23
167
|
local _attributes = {
|
|
24
168
|
ref = ref,
|
|
25
169
|
}
|
|
26
170
|
for _k, _v in props do
|
|
27
171
|
_attributes[_k] = _v
|
|
28
172
|
end
|
|
29
|
-
|
|
30
|
-
|
|
173
|
+
for _k, _v in positionProps do
|
|
174
|
+
_attributes[_k] = _v
|
|
175
|
+
end
|
|
176
|
+
_attributes.Size = positionProps.Size or UDim2.fromScale(0, 0)
|
|
177
|
+
_attributes.AutomaticSize = positionProps.AutomaticSize or Enum.AutomaticSize.XY
|
|
31
178
|
_attributes.BackgroundTransparency = intent.backgroundTransparency
|
|
32
179
|
_attributes.BackgroundColor3 = intent.backgroundColor
|
|
33
180
|
_attributes.BorderSizePixel = 0
|
|
34
|
-
|
|
181
|
+
_attributes.backgroundImage = intent.backgroundImage
|
|
182
|
+
_attributes.Change = if overlay and card.reportOverlayHeaderRect ~= nil then {
|
|
183
|
+
AbsolutePosition = function(instance)
|
|
184
|
+
return card.reportOverlayHeaderRect(instance.AbsolutePosition, instance.AbsoluteSize)
|
|
185
|
+
end,
|
|
186
|
+
AbsoluteSize = function(instance)
|
|
187
|
+
return card.reportOverlayHeaderRect(instance.AbsolutePosition, instance.AbsoluteSize)
|
|
188
|
+
end,
|
|
189
|
+
} else nil
|
|
190
|
+
local _exp = React.createElement(Padding, {
|
|
35
191
|
resolvedPadding = padding,
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
192
|
+
})
|
|
193
|
+
local _attributes_1 = {}
|
|
194
|
+
local _condition = theme.components.card.header.borderThickness
|
|
195
|
+
if _condition == nil then
|
|
196
|
+
_condition = theme.components.card.borderThickness
|
|
197
|
+
end
|
|
198
|
+
_attributes_1.Thickness = _condition
|
|
199
|
+
_attributes_1.Color = intent.borderColor
|
|
200
|
+
_attributes_1.BorderStrokePosition = Enum.BorderStrokePosition.Inner
|
|
201
|
+
return React.createElement(Container, _attributes, _exp, React.createElement("uistroke", _attributes_1), React.createElement("uicorner", {
|
|
41
202
|
TopLeftRadius = corners,
|
|
42
203
|
TopRightRadius = corners,
|
|
43
204
|
BottomLeftRadius = UDim.new(0, 0),
|
|
@@ -46,7 +207,39 @@ local CardHeader = React.forwardRef(function(props, ref)
|
|
|
46
207
|
end)
|
|
47
208
|
local CardBody = React.forwardRef(function(props, ref)
|
|
48
209
|
local theme = React.useContext(CleanThemeContext)
|
|
49
|
-
|
|
210
|
+
-- Mirrors Box.tsx's own padding resolution (CardBody wraps its
|
|
211
|
+
-- children in a Container, not a Box, so it doesn't get Box's
|
|
212
|
+
-- automatic `box.padding` application for free) — apply the card
|
|
213
|
+
-- body's own theme padding only when the caller hasn't set explicit
|
|
214
|
+
-- padding props. `card.body.padding`, when set, is an intentional
|
|
215
|
+
-- full-override escape hatch and wins wholesale over everything
|
|
216
|
+
-- below. Absent that, top/bottom fall back to the same generic
|
|
217
|
+
-- md-scale default Header/Footer use for their own padding (NOT
|
|
218
|
+
-- `box.padding`'s top/bottom) — CardBody's bottom padding stacks
|
|
219
|
+
-- directly against an in-flow CardFooter's own top padding (the
|
|
220
|
+
-- VStack's spacing is "None"), so inheriting `box.padding`'s
|
|
221
|
+
-- vertical values here would double them up with Footer's/Header's
|
|
222
|
+
-- own padding. Left/right still inherit `box.padding` since nothing
|
|
223
|
+
-- else contributes horizontal padding at that seam.
|
|
224
|
+
local paddingSourceProps = props
|
|
225
|
+
local hasCustomPadding = paddingSourceProps.top ~= nil or paddingSourceProps.bottom ~= nil or paddingSourceProps.left ~= nil or paddingSourceProps.right ~= nil or paddingSourceProps.spacing ~= nil or paddingSourceProps.padding ~= nil or paddingSourceProps.resolvedPadding ~= nil
|
|
226
|
+
local _bodyThemePadding = theme.components.card.body
|
|
227
|
+
if _bodyThemePadding ~= nil then
|
|
228
|
+
_bodyThemePadding = _bodyThemePadding.padding
|
|
229
|
+
end
|
|
230
|
+
local bodyThemePadding = _bodyThemePadding
|
|
231
|
+
local boxThemePadding = theme.components.box.padding
|
|
232
|
+
local mdPadding = SpacingHelper:GetPadding(theme, "md")
|
|
233
|
+
local paddingProps = if hasCustomPadding then paddingSourceProps elseif bodyThemePadding ~= nil then {
|
|
234
|
+
resolvedPadding = CssHelper:parseCssQuad(bodyThemePadding),
|
|
235
|
+
} else {
|
|
236
|
+
resolvedPadding = {
|
|
237
|
+
top = mdPadding,
|
|
238
|
+
bottom = mdPadding,
|
|
239
|
+
left = if boxThemePadding ~= nil then CssHelper:parseCssQuad(boxThemePadding).left else mdPadding,
|
|
240
|
+
right = if boxThemePadding ~= nil then CssHelper:parseCssQuad(boxThemePadding).right else mdPadding,
|
|
241
|
+
},
|
|
242
|
+
}
|
|
50
243
|
local _attributes = {
|
|
51
244
|
ref = ref,
|
|
52
245
|
Size = SizeHelper:GetSize(props, UDim2.fromScale(0, 0)),
|
|
@@ -55,9 +248,9 @@ local CardBody = React.forwardRef(function(props, ref)
|
|
|
55
248
|
_attributes[_k] = _v
|
|
56
249
|
end
|
|
57
250
|
_attributes.AutomaticSize = Enum.AutomaticSize.XY
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
251
|
+
local _attributes_1 = table.clone(paddingProps)
|
|
252
|
+
setmetatable(_attributes_1, nil)
|
|
253
|
+
return React.createElement(FlexItem, nil, React.createElement(Container, _attributes, React.createElement(Padding, _attributes_1), props.children))
|
|
61
254
|
end)
|
|
62
255
|
local CardFooter = React.forwardRef(function(props, ref)
|
|
63
256
|
local theme = React.useContext(CleanThemeContext)
|
|
@@ -65,24 +258,44 @@ local CardFooter = React.forwardRef(function(props, ref)
|
|
|
65
258
|
local intent = ColorHelper:getIntentColors(theme, props.intent or card.intent or "primary", "default", theme.components.card.footer.intents)
|
|
66
259
|
local padding = SpacingHelper:ResolveNumberPadding(SpacingHelper:GetPadding(theme, "md", theme.components.card.footer.spacing))
|
|
67
260
|
local corners = CssHelper:parseCssSize(theme.components.card.cornerRadius)
|
|
261
|
+
local _binding = resolveOverlayPosition(props, theme.components.card.footer.position)
|
|
262
|
+
local overlay = _binding.overlay
|
|
263
|
+
local positionProps = _binding.positionProps
|
|
68
264
|
local _attributes = {
|
|
69
265
|
ref = ref,
|
|
70
266
|
}
|
|
71
267
|
for _k, _v in props do
|
|
72
268
|
_attributes[_k] = _v
|
|
73
269
|
end
|
|
74
|
-
|
|
75
|
-
|
|
270
|
+
for _k, _v in positionProps do
|
|
271
|
+
_attributes[_k] = _v
|
|
272
|
+
end
|
|
273
|
+
_attributes.Size = positionProps.Size or UDim2.fromScale(0, 0)
|
|
274
|
+
_attributes.AutomaticSize = positionProps.AutomaticSize or Enum.AutomaticSize.XY
|
|
76
275
|
_attributes.BackgroundTransparency = intent.backgroundTransparency
|
|
77
276
|
_attributes.BackgroundColor3 = intent.backgroundColor
|
|
78
277
|
_attributes.BorderSizePixel = 0
|
|
79
|
-
|
|
278
|
+
_attributes.backgroundImage = intent.backgroundImage
|
|
279
|
+
_attributes.Change = if overlay and card.reportOverlayFooterRect ~= nil then {
|
|
280
|
+
AbsolutePosition = function(instance)
|
|
281
|
+
return card.reportOverlayFooterRect(instance.AbsolutePosition, instance.AbsoluteSize)
|
|
282
|
+
end,
|
|
283
|
+
AbsoluteSize = function(instance)
|
|
284
|
+
return card.reportOverlayFooterRect(instance.AbsolutePosition, instance.AbsoluteSize)
|
|
285
|
+
end,
|
|
286
|
+
} else nil
|
|
287
|
+
local _exp = React.createElement(Padding, {
|
|
80
288
|
resolvedPadding = padding,
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
289
|
+
})
|
|
290
|
+
local _attributes_1 = {}
|
|
291
|
+
local _condition = theme.components.card.footer.borderThickness
|
|
292
|
+
if _condition == nil then
|
|
293
|
+
_condition = theme.components.card.borderThickness
|
|
294
|
+
end
|
|
295
|
+
_attributes_1.Thickness = _condition
|
|
296
|
+
_attributes_1.Color = intent.borderColor
|
|
297
|
+
_attributes_1.BorderStrokePosition = Enum.BorderStrokePosition.Inner
|
|
298
|
+
return React.createElement(Container, _attributes, _exp, React.createElement("uistroke", _attributes_1), React.createElement("uicorner", {
|
|
86
299
|
TopLeftRadius = UDim.new(0, 0),
|
|
87
300
|
TopRightRadius = UDim.new(0, 0),
|
|
88
301
|
BottomLeftRadius = corners,
|
|
@@ -91,13 +304,152 @@ local CardFooter = React.forwardRef(function(props, ref)
|
|
|
91
304
|
end)
|
|
92
305
|
local Card = React.forwardRef(function(props, ref)
|
|
93
306
|
local theme = React.useContext(CleanThemeContext)
|
|
307
|
+
-- Overlay clearance: an overlay header (see resolveOverlayPosition)
|
|
308
|
+
-- is pulled out of the VStack entirely, so nothing reserves space
|
|
309
|
+
-- for it — its rendered box typically extends downward past its own
|
|
310
|
+
-- anchor point and overlaps into the top of the Box. These two
|
|
311
|
+
-- pieces of state capture the header's reported rect (via
|
|
312
|
+
-- CardContext.reportOverlayHeaderRect, set on CardHeader below) and
|
|
313
|
+
-- the overlay wrapper frame's own AbsolutePosition, so the amount of
|
|
314
|
+
-- that overlap can be measured and reserved as extra top padding on
|
|
315
|
+
-- the Box (see headerClearance/boxProps below). Both are undefined
|
|
316
|
+
-- until their first Change event fires after mount, which is the
|
|
317
|
+
-- same measure-then-settle characteristic Accordion.tsx accepts for
|
|
318
|
+
-- its own AbsoluteSize-driven measurements.
|
|
319
|
+
local headerRect, setHeaderRect = React.useState()
|
|
320
|
+
local footerRect, setFooterRect = React.useState()
|
|
321
|
+
local wrapperAbsoluteY, setWrapperAbsoluteY = React.useState()
|
|
322
|
+
local wrapperAbsoluteSize, setWrapperAbsoluteSize = React.useState()
|
|
323
|
+
local overlayWrapperRef = React.useRef()
|
|
324
|
+
local reportOverlayHeaderRect = React.useCallback(function(position, size)
|
|
325
|
+
setHeaderRect({
|
|
326
|
+
position = position,
|
|
327
|
+
size = size,
|
|
328
|
+
})
|
|
329
|
+
end, {})
|
|
330
|
+
local reportOverlayFooterRect = React.useCallback(function(position, size)
|
|
331
|
+
setFooterRect({
|
|
332
|
+
position = position,
|
|
333
|
+
size = size,
|
|
334
|
+
})
|
|
335
|
+
end, {})
|
|
94
336
|
local contextValue = React.useMemo(function()
|
|
95
337
|
return {
|
|
96
338
|
intent = props.intent,
|
|
339
|
+
reportOverlayHeaderRect = reportOverlayHeaderRect,
|
|
340
|
+
reportOverlayFooterRect = reportOverlayFooterRect,
|
|
97
341
|
}
|
|
98
|
-
end, { props.intent })
|
|
342
|
+
end, { props.intent, reportOverlayHeaderRect, reportOverlayFooterRect })
|
|
99
343
|
local intent = ColorHelper:getIntentColors(theme, props.intent or "primary", "default", theme.components.card.header.intents)
|
|
100
|
-
|
|
344
|
+
-- Pull out a Header/Footer that wants overlay placement so it can be
|
|
345
|
+
-- rendered outside the VStack below (see resolveOverlayPosition above
|
|
346
|
+
-- for why it can't stay inside the VStack and still be positioned).
|
|
347
|
+
-- Everything else renders in place, in its original order.
|
|
348
|
+
local _binding = React.useMemo(function()
|
|
349
|
+
local flow = {}
|
|
350
|
+
local header
|
|
351
|
+
local footer
|
|
352
|
+
React.Children.forEach(props.children, function(child)
|
|
353
|
+
if child == nil then
|
|
354
|
+
return nil
|
|
355
|
+
end
|
|
356
|
+
if React.isValidElement(child) and child.type == CardHeader and header == nil then
|
|
357
|
+
local headerElement = child
|
|
358
|
+
local _condition = headerElement.props.overlay
|
|
359
|
+
if _condition == nil then
|
|
360
|
+
local _result = theme.components.card.header.position
|
|
361
|
+
if _result ~= nil then
|
|
362
|
+
_result = _result.position
|
|
363
|
+
end
|
|
364
|
+
_condition = (_result == "absolute")
|
|
365
|
+
end
|
|
366
|
+
if _condition then
|
|
367
|
+
header = headerElement
|
|
368
|
+
return nil
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
if React.isValidElement(child) and child.type == CardFooter and footer == nil then
|
|
372
|
+
local footerElement = child
|
|
373
|
+
local _condition = footerElement.props.overlay
|
|
374
|
+
if _condition == nil then
|
|
375
|
+
local _result = theme.components.card.footer.position
|
|
376
|
+
if _result ~= nil then
|
|
377
|
+
_result = _result.position
|
|
378
|
+
end
|
|
379
|
+
_condition = (_result == "absolute")
|
|
380
|
+
end
|
|
381
|
+
if _condition then
|
|
382
|
+
footer = footerElement
|
|
383
|
+
return nil
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
local _child = child
|
|
387
|
+
table.insert(flow, _child)
|
|
388
|
+
end)
|
|
389
|
+
return {
|
|
390
|
+
flowChildren = flow,
|
|
391
|
+
overlayHeader = header,
|
|
392
|
+
overlayFooter = footer,
|
|
393
|
+
}
|
|
394
|
+
end, { props.children, theme })
|
|
395
|
+
local flowChildren = _binding.flowChildren
|
|
396
|
+
local overlayHeader = _binding.overlayHeader
|
|
397
|
+
local overlayFooter = _binding.overlayFooter
|
|
398
|
+
local hasOverlay = overlayHeader ~= nil or overlayFooter ~= nil
|
|
399
|
+
-- How far the overlay header's bottom edge extends past the
|
|
400
|
+
-- wrapper's (i.e. the Box's) top edge — 0 when there's no overlap
|
|
401
|
+
-- (e.g. a small/no theme offset) or nothing has been measured yet.
|
|
402
|
+
local headerClearance = if overlayHeader ~= nil and headerRect ~= nil and wrapperAbsoluteY ~= nil then math.max(0, (headerRect.position.Y + headerRect.size.Y) - wrapperAbsoluteY) else 0
|
|
403
|
+
-- Same idea, mirrored for the footer: the wrapper's bottom edge
|
|
404
|
+
-- (its top plus its own height) minus the footer's reported top
|
|
405
|
+
-- edge (AbsolutePosition is always the top-left corner regardless
|
|
406
|
+
-- of AnchorPoint) is how far the footer's top edge sits above the
|
|
407
|
+
-- Box's bottom edge, i.e. how much it overlaps upward into it.
|
|
408
|
+
local wrapperBottomY = if wrapperAbsoluteY ~= nil and wrapperAbsoluteSize ~= nil then wrapperAbsoluteY + wrapperAbsoluteSize.Y else nil
|
|
409
|
+
local footerClearance = if overlayFooter ~= nil and footerRect ~= nil and wrapperBottomY ~= nil then math.max(0, wrapperBottomY - footerRect.position.Y) else 0
|
|
410
|
+
-- The Box below now sits inside an extra positioning frame (see
|
|
411
|
+
-- boxWithOverlay), so its own Position/AnchorPoint/ZIndex/LayoutOrder
|
|
412
|
+
-- are cleared here to avoid double-applying them — the wrapper frame
|
|
413
|
+
-- owns those instead.
|
|
414
|
+
local _result
|
|
415
|
+
if hasOverlay then
|
|
416
|
+
local _object = table.clone(props)
|
|
417
|
+
setmetatable(_object, nil)
|
|
418
|
+
_object.Position = nil
|
|
419
|
+
_object.AnchorPoint = nil
|
|
420
|
+
_object.top = nil
|
|
421
|
+
_object.left = nil
|
|
422
|
+
_object.right = nil
|
|
423
|
+
_object.bottom = nil
|
|
424
|
+
_object.ZIndex = nil
|
|
425
|
+
_object.LayoutOrder = nil
|
|
426
|
+
_result = _object
|
|
427
|
+
else
|
|
428
|
+
_result = props
|
|
429
|
+
end
|
|
430
|
+
local boxProps = _result
|
|
431
|
+
-- When an overlay header and/or footer measurably overlaps into the
|
|
432
|
+
-- Box (headerClearance/footerClearance > 0), reserve that much extra
|
|
433
|
+
-- top/bottom padding via resolvedPadding — this takes over Box's own
|
|
434
|
+
-- outer padding, which is harmless since Card always forces
|
|
435
|
+
-- spacing="None" on Box below anyway (so it was always 0/0/0/0 until
|
|
436
|
+
-- now).
|
|
437
|
+
local _result_1
|
|
438
|
+
if headerClearance > 0 or footerClearance > 0 then
|
|
439
|
+
local _object = table.clone(boxProps)
|
|
440
|
+
setmetatable(_object, nil)
|
|
441
|
+
_object.resolvedPadding = {
|
|
442
|
+
top = headerClearance,
|
|
443
|
+
bottom = footerClearance,
|
|
444
|
+
left = 0,
|
|
445
|
+
right = 0,
|
|
446
|
+
}
|
|
447
|
+
_result_1 = _object
|
|
448
|
+
else
|
|
449
|
+
_result_1 = boxProps
|
|
450
|
+
end
|
|
451
|
+
local boxPropsWithOverlayClearance = _result_1
|
|
452
|
+
local _attributes = table.clone(boxPropsWithOverlayClearance)
|
|
101
453
|
setmetatable(_attributes, nil)
|
|
102
454
|
_attributes.ref = ref
|
|
103
455
|
_attributes.center = nil
|
|
@@ -105,7 +457,47 @@ local Card = React.forwardRef(function(props, ref)
|
|
|
105
457
|
_attributes["border-color"] = intent.borderColor
|
|
106
458
|
local cardBox = (React.createElement(Box, _attributes, React.createElement(VStack, {
|
|
107
459
|
spacing = "None",
|
|
108
|
-
},
|
|
460
|
+
}, flowChildren)))
|
|
461
|
+
-- ClipsDescendants is off so an overlay header/footer can protrude
|
|
462
|
+
-- past the Box's own edges (e.g. a plaque mounted above the top
|
|
463
|
+
-- border). This frame takes over the Position/AnchorPoint the Box
|
|
464
|
+
-- would otherwise have used, and auto-sizes to hug the Box (plus
|
|
465
|
+
-- whatever the overlay siblings protrude by).
|
|
466
|
+
--
|
|
467
|
+
-- `center` is stripped before deriving Position/AnchorPoint here,
|
|
468
|
+
-- the same way `cardBox`'s Box always gets `center={undefined}`:
|
|
469
|
+
-- when `center` is set, centering is handled by the outer
|
|
470
|
+
-- `isCentered` wrapper below (a UIListLayout that centers this
|
|
471
|
+
-- whole frame), not by this frame's own Position/AnchorPoint. If
|
|
472
|
+
-- both applied `center` at once, the UIListLayout would place the
|
|
473
|
+
-- frame using an (0,0)-anchor assumption while the frame itself
|
|
474
|
+
-- reported a (0.5,0.5) AnchorPoint, offsetting it by half its own
|
|
475
|
+
-- size and letting its (ClipsDescendants=false) contents spill out.
|
|
476
|
+
-- Explicit top/left/right/bottom/Position/AnchorPoint overrides are
|
|
477
|
+
-- unaffected and still apply directly to this frame.
|
|
478
|
+
local _object = table.clone(props)
|
|
479
|
+
setmetatable(_object, nil)
|
|
480
|
+
_object.center = nil
|
|
481
|
+
local wrapperPositionProps = _object
|
|
482
|
+
local boxWithOverlay = if hasOverlay then (React.createElement("frame", {
|
|
483
|
+
ref = overlayWrapperRef,
|
|
484
|
+
BackgroundTransparency = 1,
|
|
485
|
+
ClipsDescendants = false,
|
|
486
|
+
Size = SizeHelper:GetSize(props, UDim2.fromScale(1, 1)),
|
|
487
|
+
AutomaticSize = SizeHelper:GetAutoSize(props),
|
|
488
|
+
Position = SizeHelper:GetPosition(wrapperPositionProps),
|
|
489
|
+
AnchorPoint = SizeHelper:GetAnchor(wrapperPositionProps),
|
|
490
|
+
ZIndex = props.ZIndex,
|
|
491
|
+
LayoutOrder = props.LayoutOrder,
|
|
492
|
+
Change = {
|
|
493
|
+
AbsolutePosition = function(instance)
|
|
494
|
+
return setWrapperAbsoluteY(instance.AbsolutePosition.Y)
|
|
495
|
+
end,
|
|
496
|
+
AbsoluteSize = function(instance)
|
|
497
|
+
return setWrapperAbsoluteSize(instance.AbsoluteSize)
|
|
498
|
+
end,
|
|
499
|
+
},
|
|
500
|
+
}, cardBox, overlayHeader, overlayFooter)) else cardBox
|
|
109
501
|
local isCentered = props.center == true and props.Position == nil and props.AnchorPoint == nil
|
|
110
502
|
return React.createElement(CardContext.Provider, {
|
|
111
503
|
value = contextValue,
|
|
@@ -117,7 +509,7 @@ local Card = React.forwardRef(function(props, ref)
|
|
|
117
509
|
FillDirection = Enum.FillDirection.Horizontal,
|
|
118
510
|
HorizontalAlignment = Enum.HorizontalAlignment.Center,
|
|
119
511
|
VerticalAlignment = Enum.VerticalAlignment.Center,
|
|
120
|
-
}),
|
|
512
|
+
}), boxWithOverlay)) else boxWithOverlay)
|
|
121
513
|
end)
|
|
122
514
|
Card.Header = CardHeader
|
|
123
515
|
Card.Footer = CardFooter
|
|
@@ -51,14 +51,52 @@ function Icon(props)
|
|
|
51
51
|
setmetatable(_attributes, nil)
|
|
52
52
|
return React.createElement(SpinningIcon, _attributes)
|
|
53
53
|
end
|
|
54
|
-
|
|
54
|
+
local _attributes = {
|
|
55
|
+
AnchorPoint = props.AnchorPoint,
|
|
55
56
|
Rotation = props.Rotation,
|
|
56
57
|
Size = props.Size or UDim2.fromOffset(size, size),
|
|
58
|
+
Position = props.Position,
|
|
57
59
|
LayoutOrder = props.LayoutOrder,
|
|
58
60
|
Image = if iconId == nil then nil else `rbxassetid://{iconId}`,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
}
|
|
62
|
+
local _condition = props.BackgroundTransparency
|
|
63
|
+
if _condition == nil then
|
|
64
|
+
_condition = 1
|
|
65
|
+
end
|
|
66
|
+
_attributes.BackgroundTransparency = _condition
|
|
67
|
+
_attributes.ImageColor3 = props.color or theme.colors.intents.primary.default.textColor
|
|
68
|
+
_attributes.ZIndex = props.ZIndex
|
|
69
|
+
_attributes.Visible = props.Visible
|
|
70
|
+
_attributes.Active = props.Active
|
|
71
|
+
_attributes.Archivable = props.Archivable
|
|
72
|
+
_attributes.BackgroundColor3 = props.BackgroundColor3
|
|
73
|
+
_attributes.BorderColor3 = props.BorderColor3
|
|
74
|
+
_attributes.BorderMode = props.BorderMode
|
|
75
|
+
_attributes.BorderSizePixel = props.BorderSizePixel
|
|
76
|
+
_attributes.ClipsDescendants = props.ClipsDescendants
|
|
77
|
+
_attributes.Selectable = props.Selectable
|
|
78
|
+
_attributes.SelectionImageObject = props.SelectionImageObject
|
|
79
|
+
_attributes.SizeConstraint = props.SizeConstraint
|
|
80
|
+
_attributes.Tag = props.Tag
|
|
81
|
+
_attributes.AutoLocalize = props.AutoLocalize
|
|
82
|
+
_attributes.RootLocalizationTable = props.RootLocalizationTable
|
|
83
|
+
_attributes.NextSelectionDown = props.NextSelectionDown
|
|
84
|
+
_attributes.NextSelectionLeft = props.NextSelectionLeft
|
|
85
|
+
_attributes.NextSelectionRight = props.NextSelectionRight
|
|
86
|
+
_attributes.NextSelectionUp = props.NextSelectionUp
|
|
87
|
+
_attributes.SelectionGroup = props.SelectionGroup
|
|
88
|
+
_attributes.SelectionOrder = props.SelectionOrder
|
|
89
|
+
_attributes.ImageRectOffset = props.ImageRectOffset
|
|
90
|
+
_attributes.ImageRectSize = props.ImageRectSize
|
|
91
|
+
_attributes.ImageTransparency = props.ImageTransparency
|
|
92
|
+
_attributes.ResampleMode = props.ResampleMode
|
|
93
|
+
_attributes.ScaleType = props.ScaleType
|
|
94
|
+
_attributes.SliceCenter = props.SliceCenter
|
|
95
|
+
_attributes.SliceScale = props.SliceScale
|
|
96
|
+
_attributes.TileSize = props.TileSize
|
|
97
|
+
_attributes.Change = props.Change
|
|
98
|
+
_attributes.Event = props.Event
|
|
99
|
+
return React.createElement("imagelabel", _attributes)
|
|
62
100
|
end
|
|
63
101
|
return {
|
|
64
102
|
Icon = Icon,
|
|
@@ -8,6 +8,7 @@ interface TextProps extends React.InstanceProps<TextLabel> {
|
|
|
8
8
|
weight?: Enum.FontWeight | "bold";
|
|
9
9
|
align?: "Left" | "Right" | "Center";
|
|
10
10
|
TextWrap?: boolean;
|
|
11
|
+
letterSpacing?: number;
|
|
11
12
|
}
|
|
12
13
|
export declare const Text: React.ForwardRefExoticComponent<Omit<TextProps, "ref"> & React.RefAttributes<TextLabel>>;
|
|
13
14
|
export {};
|