Skip to content

Commit

Permalink
Add spritesheet icon support (#50)
Browse files Browse the repository at this point in the history
* Add spritesheet icon support

* refactor baseicon

* update changelog

* fix storybook for luau-analyze

* fix doc comments

* fix dropdown item icon alignment

---------

Co-authored-by: sircfenner <sircfenner@users.noreply.github.com>
  • Loading branch information
EgoMoose and sircfenner authored Jan 3, 2025
1 parent 4ed1141 commit 32e4f05
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/Components/Button.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
25 changes: 15 additions & 10 deletions src/Components/Dropdown/DropdownItem.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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", {
Expand Down Expand Up @@ -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),
Expand Down
6 changes: 6 additions & 0 deletions src/Components/Dropdown/Types.luau
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ 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 = {
Image: string,
Size: Vector2,
Transparency: number?,
Color: Color3?,
ResampleMode: Enum.ResamplerMode?,
RectOffset: Vector2?,
RectSize: Vector2?,
UseThemeColor: boolean?,
}

Expand Down
46 changes: 27 additions & 19 deletions src/Components/Foundation/BaseButton.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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 & {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
33 changes: 33 additions & 0 deletions src/Components/Foundation/BaseIcon.luau
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions src/Components/MainButton.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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?
]=]

--[=[
Expand Down
16 changes: 8 additions & 8 deletions src/Stories/Button.story.luau
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions src/Stories/Helpers/studiocomponents.storybook.luau
Original file line number Diff line number Diff line change
@@ -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,
},
}

0 comments on commit 32e4f05

Please sign in to comment.