diff --git a/CHANGELOG.md b/CHANGELOG.md index d7a6294..f97623c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- Added RectSize, RectOffset, and ResampleMode to icon props available in Button, MainButton, and Dropdown + ## 1.1.0 - Fixed image links in documentation diff --git a/src/Components/Button.luau b/src/Components/Button.luau index c42d51e..8d757c9 100644 --- a/src/Components/Button.luau +++ b/src/Components/Button.luau @@ -46,6 +46,9 @@ local BaseButton = require("./Foundation/BaseButton") @field Color Color3? @field UseThemeColor boolean? @field Alignment HorizontalAlignment? + @field ResampleMode Enum.ResamplerMode? + @field RectOffset Vector2? + @field RectSize Vector2? The `Alignment` prop is used to configure which side of any text the icon appears on. Left-alignment is the default and center-alignment is not supported. diff --git a/src/Components/Dropdown/DropdownItem.luau b/src/Components/Dropdown/DropdownItem.luau index 22d8d8c..fadb530 100644 --- a/src/Components/Dropdown/DropdownItem.luau +++ b/src/Components/Dropdown/DropdownItem.luau @@ -3,6 +3,8 @@ local React = require("@pkg/@jsdotlua/react") local Constants = require("../../Constants") local useTheme = require("../../Hooks/useTheme") +local BaseIcon = require("../Foundation/BaseIcon") + local DropdownTypes = require("./Types") type DropdownItemProps = { @@ -27,13 +29,24 @@ local function DropdownItem(props: DropdownItemProps) modifier = Enum.StudioStyleGuideModifier.Hover end - local iconColor = Color3.fromRGB(255, 255, 255) + local iconNode: React.Node? if props.Icon then + local iconColor = Color3.fromRGB(255, 255, 255) if props.Icon.UseThemeColor then iconColor = theme:GetColor(Enum.StudioStyleGuideColor.MainText) elseif props.Icon.Color then iconColor = props.Icon.Color end + + local iconProps = (table.clone(props.Icon) :: any) :: BaseIcon.BaseIconProps + iconProps.Color = iconColor + iconProps.AnchorPoint = Vector2.new(0, 0.5) + iconProps.Position = UDim2.fromScale(0, 0.5) + iconProps.Size = UDim2.fromOffset(props.Icon.Size.X, props.Icon.Size.Y) + iconProps.Disabled = nil + iconProps.LayoutOrder = nil + + iconNode = React.createElement(BaseIcon, iconProps) end return React.createElement("Frame", { @@ -66,15 +79,7 @@ local function DropdownItem(props: DropdownItemProps) PaddingLeft = UDim.new(0, props.TextInset), PaddingBottom = UDim.new(0, 2), }), - Icon = props.Icon and React.createElement("ImageLabel", { - AnchorPoint = Vector2.new(0, 0.5), - Position = UDim2.fromScale(0, 0.5), - Size = UDim2.fromOffset(props.Icon.Size.X, props.Icon.Size.Y), - BackgroundTransparency = 1, - Image = props.Icon.Image, - ImageTransparency = props.Icon.Transparency or 0, - ImageColor3 = iconColor, - }), + Icon = iconNode, Label = React.createElement("TextLabel", { BackgroundTransparency = 1, AnchorPoint = Vector2.new(1, 0), diff --git a/src/Components/Dropdown/Types.luau b/src/Components/Dropdown/Types.luau index 319d88c..13b4e11 100644 --- a/src/Components/Dropdown/Types.luau +++ b/src/Components/Dropdown/Types.luau @@ -29,6 +29,9 @@ export type DropdownItemDetail = { @field Transparency number? @field Color Color3? @field UseThemeColor boolean? + @field ResampleMode Enum.ResamplerMode? + @field RectOffset Vector2? + @field RectSize Vector2? ]=] export type DropdownItemIcon = { @@ -36,6 +39,9 @@ export type DropdownItemIcon = { Size: Vector2, Transparency: number?, Color: Color3?, + ResampleMode: Enum.ResamplerMode?, + RectOffset: Vector2?, + RectSize: Vector2?, UseThemeColor: boolean?, } diff --git a/src/Components/Foundation/BaseButton.luau b/src/Components/Foundation/BaseButton.luau index 61ae677..0e130db 100644 --- a/src/Components/Foundation/BaseButton.luau +++ b/src/Components/Foundation/BaseButton.luau @@ -6,24 +6,31 @@ local Constants = require("../../Constants") local getTextSize = require("../../getTextSize") local useTheme = require("../../Hooks/useTheme") +local BaseIcon = require("./BaseIcon") + local PADDING_X = 8 local PADDING_Y = 4 local DEFAULT_HEIGHT = Constants.DefaultButtonHeight +export type BaseButtonIconProps = { + Image: string, + Size: Vector2, + Transparency: number?, + Color: Color3?, + ResampleMode: Enum.ResamplerMode?, + RectOffset: Vector2?, + RectSize: Vector2?, + UseThemeColor: boolean?, + Alignment: Enum.HorizontalAlignment?, +} + export type BaseButtonConsumerProps = CommonProps.T & { AutomaticSize: Enum.AutomaticSize?, OnActivated: (() -> ())?, Selected: boolean?, Text: string?, TextTransparency: number?, - Icon: { - Image: string, - Size: Vector2, - Transparency: number?, - Color: Color3?, - UseThemeColor: boolean?, - Alignment: Enum.HorizontalAlignment?, - }?, + Icon: BaseButtonIconProps?, } export type BaseButtonProps = BaseButtonConsumerProps & { @@ -78,6 +85,17 @@ local function BaseButton(props: BaseButtonProps) size = UDim2.new(size.Width, UDim.new(0, math.max(DEFAULT_HEIGHT, contentHeight + PADDING_Y * 2))) end + local iconNode: React.Node? + if props.Icon then + local iconProps = (table.clone(props.Icon) :: any) :: BaseIcon.BaseIconProps + iconProps.Disabled = props.Disabled + iconProps.Color = iconProps.Color or if props.Icon.UseThemeColor then textColor else nil + iconProps.LayoutOrder = if props.Icon.Alignment == Enum.HorizontalAlignment.Right then 3 else 1 + iconProps.Size = UDim2.fromOffset(props.Icon.Size.X, props.Icon.Size.Y) + + iconNode = React.createElement(BaseIcon, iconProps) + end + return React.createElement("TextButton", { AutoButtonColor = false, AnchorPoint = props.AnchorPoint, @@ -115,17 +133,7 @@ local function BaseButton(props: BaseButtonProps) HorizontalAlignment = Enum.HorizontalAlignment.Center, VerticalAlignment = Enum.VerticalAlignment.Center, }), - Icon = props.Icon and React.createElement("ImageLabel", { - Image = props.Icon.Image, - Size = UDim2.fromOffset(props.Icon.Size.X, props.Icon.Size.Y), - LayoutOrder = if props.Icon.Alignment == Enum.HorizontalAlignment.Right then 3 else 1, - BackgroundTransparency = 1, - ImageColor3 = if props.Icon.Color - then props.Icon.Color - elseif props.Icon.UseThemeColor then textColor - else nil, - ImageTransparency = 1 - (1 - (props.Icon.Transparency or 0)) * (1 - if props.Disabled then 0.2 else 0), - }), + Icon = iconNode, Label = props.Text and React.createElement("TextLabel", { TextColor3 = textColor, Font = Constants.DefaultFont, diff --git a/src/Components/Foundation/BaseIcon.luau b/src/Components/Foundation/BaseIcon.luau new file mode 100644 index 0000000..4dd7b55 --- /dev/null +++ b/src/Components/Foundation/BaseIcon.luau @@ -0,0 +1,33 @@ +local React = require("@pkg/@jsdotlua/react") + +local CommonProps = require("../../CommonProps") + +export type BaseIconConsumerProps = CommonProps.T & { + Image: string, + Transparency: number?, + Color: Color3?, + ResampleMode: Enum.ResamplerMode?, + RectOffset: Vector2?, + RectSize: Vector2?, +} + +export type BaseIconProps = BaseIconConsumerProps + +local function BaseIcon(props: BaseIconProps) + return React.createElement("ImageLabel", { + Size = props.Size, + Position = props.Position, + AnchorPoint = props.AnchorPoint, + LayoutOrder = props.LayoutOrder, + ZIndex = props.ZIndex, + BackgroundTransparency = 1, + Image = props.Image, + ImageColor3 = props.Color, + ImageTransparency = 1 - (1 - (props.Transparency or 0)) * (1 - if props.Disabled then 0.2 else 0), + ImageRectOffset = props.RectOffset, + ImageRectSize = props.RectSize, + ResampleMode = props.ResampleMode, + }) +end + +return BaseIcon diff --git a/src/Components/MainButton.luau b/src/Components/MainButton.luau index eb143a7..47d4631 100644 --- a/src/Components/MainButton.luau +++ b/src/Components/MainButton.luau @@ -25,6 +25,9 @@ local BaseButton = require("./Foundation/BaseButton") @field Color Color3? @field UseThemeColor boolean? @field Alignment HorizontalAlignment? + @field ResampleMode Enum.ResamplerMode? + @field RectOffset Vector2? + @field RectSize Vector2? ]=] --[=[ diff --git a/src/Stories/Button.story.luau b/src/Stories/Button.story.luau index f851b6b..74245e1 100644 --- a/src/Stories/Button.story.luau +++ b/src/Stories/Button.story.luau @@ -10,14 +10,14 @@ local function StoryButton(props: { }) return React.createElement(Button, { LayoutOrder = if props.Disabled then 2 else 1, - Icon = if props.HasIcon - then { - Image = "rbxasset://studio_svg_textures/Shared/InsertableObjects/Dark/Standard/Part.png", - Size = Vector2.one * 16, - UseThemeColor = true, - Alignment = Enum.HorizontalAlignment.Left, - } - else nil, + Icon = props.HasIcon and { + Image = "rbxassetid://18786011824", + UseThemeColor = true, + Size = Vector2.new(16, 16), + Alignment = Enum.HorizontalAlignment.Left, + RectOffset = Vector2.new(1000, 0), + RectSize = Vector2.new(16, 16), + } :: any, Text = props.Text, OnActivated = if not props.Disabled then function() end else nil, Disabled = props.Disabled, diff --git a/src/Stories/Helpers/studiocomponents.storybook.luau b/src/Stories/Helpers/studiocomponents.storybook.luau new file mode 100644 index 0000000..8ed2195 --- /dev/null +++ b/src/Stories/Helpers/studiocomponents.storybook.luau @@ -0,0 +1,15 @@ +--!nocheck + +local React = require("@pkg/@jsdotlua/react") +local ReactRoblox = require("@pkg/@jsdotlua/react-roblox") + +return { + name = "StudioComponents", + storyRoots = { + script.Parent.Parent, + }, + packages = { + React = React, + ReactRoblox = ReactRoblox, + }, +}