@nrbx/topbar-components 1.2.3 → 1.3.0
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/README.md +22 -10
- package/out/components/icon.d.ts +7 -3
- package/out/components/icon.luau +24 -5
- package/out/components/overflow.luau +1 -1
- package/out/style.luau +2 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<div align="center" id="top">
|
|
2
|
-
<img src="https://
|
|
3
|
-
<img src="https://github.com/nn140/Branding/blob/main/LogoBlack-Full.png?raw=true" alt="NN140.UK logo" width="800"/>
|
|
2
|
+
<img src="https://r2.nrbx.nn140.uk/img/NRBX-Banner.png" alt="NRBX logo" width="1000"/>
|
|
4
3
|
<br />
|
|
5
4
|
<br />
|
|
6
5
|
<img src="https://img.shields.io/badge/Stripe-Donate%20to%20support%20NN140.UK-1b1b1b?style=for-the-badge&labelColor=6860ff&logo=stripe&logoColor=ffffff&logoSize=auto&link=https%3A%2F%2Fdonate.stripe.com%2F9B6eVdbTd4n1a6H1yXa3u04&link=https%3A%2F%2Fdonate.stripe.com%2F9B6eVdbTd4n1a6H1yXa3u04" alt="Badge">
|
|
@@ -93,13 +92,27 @@ Dock containers (`<LeftDock>`, `<CenterDock>`, `<RightDock>`) are still availabl
|
|
|
93
92
|
|
|
94
93
|
The disabled overlay transparency and color are configurable via the stylesheet `sizing` section.
|
|
95
94
|
|
|
95
|
+
#### Click behaviour and the `toggle` prop
|
|
96
|
+
|
|
97
|
+
By default an icon is a **single-click button**: clicking it briefly lights up the background (and darkens the label) and then animates back, firing `onClick` once. It does not change its selection state.
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<Icon text="Home" onClick={() => goHome()} /> {/* standard click button */}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
To make an icon a persistent toggle, pass the `toggle` prop. Clicking it switches between selected and deselected: `selected` fires when toggled on (button stays lit) and `deselected` fires when toggled off.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
<Icon text="Mute" toggle selected={() => mute()} deselected={() => unmute()} />
|
|
107
|
+
```
|
|
108
|
+
|
|
96
109
|
#### Dropdowns
|
|
97
110
|
|
|
98
111
|
You can add a dropdown to an icon by mounting `<Dropdown />` component as it's child.
|
|
99
112
|
Dropdowns & TopbarProvider have a property called `selectionMode`, which lets you specify how many icons can be selected at once.
|
|
100
113
|
|
|
101
114
|
```tsx
|
|
102
|
-
<Icon text="Skins">
|
|
115
|
+
<Icon text="Skins" toggle>
|
|
103
116
|
<Dropdown selectionMode="Single">
|
|
104
117
|
<Icon text="yellow" selected={() => chooseSkin("yellow")} />
|
|
105
118
|
<Icon text="red" selected={() => chooseSkin("red")} />
|
|
@@ -107,7 +120,7 @@ Dropdowns & TopbarProvider have a property called `selectionMode`, which lets yo
|
|
|
107
120
|
</Icon>
|
|
108
121
|
```
|
|
109
122
|
|
|
110
|
-
Dropdowns **can be nested.**
|
|
123
|
+
Because a dropdown stays open while its parent icon is selected, the parent must opt in to toggle behaviour with the `toggle` prop. Dropdowns **can be nested.**
|
|
111
124
|
|
|
112
125
|
#### Hover animations
|
|
113
126
|
|
|
@@ -142,10 +155,10 @@ Badge styling (colors, position, corner radius, border) is controlled via `style
|
|
|
142
155
|
|
|
143
156
|
#### Toggle keys
|
|
144
157
|
|
|
145
|
-
Bind a keyboard key to toggle an icon on/off with the `toggleKey` prop:
|
|
158
|
+
Bind a keyboard key to toggle an icon on/off with the `toggleKey` prop (requires the `toggle` prop):
|
|
146
159
|
|
|
147
160
|
```tsx
|
|
148
|
-
<Icon text="Menu" toggleKey={Enum.KeyCode.M}
|
|
161
|
+
<Icon text="Menu" toggleKey={Enum.KeyCode.M} toggle />
|
|
149
162
|
```
|
|
150
163
|
|
|
151
164
|
Any `Enum.KeyCode` value works. The key binding only activates while the icon is mounted.
|
|
@@ -173,7 +186,7 @@ Tooltip appearance (colors, font, padding, border) is controlled via `stylesheet
|
|
|
173
186
|
Use `<CustomDropdown>` when you need to show rich, arbitrary content in a dropdown panel - not just child `<Icon>` elements:
|
|
174
187
|
|
|
175
188
|
```tsx
|
|
176
|
-
<Icon text="Info"
|
|
189
|
+
<Icon text="Info" toggle>
|
|
177
190
|
<CustomDropdown width={250} maxHeight={180}>
|
|
178
191
|
<textlabel Text="Custom content here!" />
|
|
179
192
|
<textbutton Text="A button" />
|
|
@@ -237,7 +250,7 @@ import { Stylesheet } from "@nrbx/topbar-components";
|
|
|
237
250
|
}}>
|
|
238
251
|
<TopbarProvider>
|
|
239
252
|
<LeftDock>
|
|
240
|
-
<Icon text="Skins">
|
|
253
|
+
<Icon text="Skins" toggle>
|
|
241
254
|
<Dropdown selectionMode="Single">
|
|
242
255
|
<Icon text="yellow" selected={() => chooseSkin("yellow")} />
|
|
243
256
|
<Icon text="red" selected={() => chooseSkin("red")} />
|
|
@@ -382,6 +395,5 @@ Package is licensed under the MIT License.
|
|
|
382
395
|
<img src="https://img.shields.io/badge/Stripe-Donate%20to%20Support%20NN140.UK%20(RECCURING)-1b1b1b?style=for-the-badge&labelColor=6860ff&logo=stripe&logoColor=ffffff&logoSize=auto&link=https%3A%2F%2Fdonate.stripe.com%2FdRm9ATe1laLpgv5b9xa3u05&link=https%3A%2F%2Fdonate.stripe.com%2FdRm9ATe1laLpgv5b9xa3u05" alt="Badge">
|
|
383
396
|
<br />
|
|
384
397
|
<br />
|
|
385
|
-
<img src="https://
|
|
386
|
-
<img src="https://github.com/nn140/Branding/blob/main/LogoWhite-Full.png?raw=true" alt="NN140.UK logo" width="800"/>
|
|
398
|
+
<img src="https://r2.nrbx.nn140.uk/img/NRBX-Banner.png" alt="NRBX logo" width="1000"/>
|
|
387
399
|
</div>
|
package/out/components/icon.d.ts
CHANGED
|
@@ -55,8 +55,12 @@ export interface IconProps extends React.PropsWithChildren {
|
|
|
55
55
|
textAlignment?: StateDependent<Enum.TextXAlignment>;
|
|
56
56
|
/** Whether the label supports rich text markup. */
|
|
57
57
|
richText?: StateDependent<boolean>;
|
|
58
|
-
/**
|
|
59
|
-
|
|
58
|
+
/**
|
|
59
|
+
* When `true`, clicking the icon toggles between selected and deselected.
|
|
60
|
+
* When `false` (the default), clicking briefly lights the icon up and fires
|
|
61
|
+
* {@link onClick} once without changing the selection state.
|
|
62
|
+
*/
|
|
63
|
+
toggle?: boolean;
|
|
60
64
|
/** When `true`, the icon ignores all clicks, hover, and state changes. */
|
|
61
65
|
static?: boolean;
|
|
62
66
|
/** When `true`, the icon is dimmed and non-interactive. */
|
|
@@ -85,7 +89,7 @@ export interface IconProps extends React.PropsWithChildren {
|
|
|
85
89
|
unhover?: () => void;
|
|
86
90
|
/** Callback fired whenever the state changes (receives the new state). */
|
|
87
91
|
stateChanged?: (state: IconState) => void;
|
|
88
|
-
/** Callback fired on left click
|
|
92
|
+
/** Callback fired on left click. */
|
|
89
93
|
onClick?: () => void;
|
|
90
94
|
/** Callback fired on right click. */
|
|
91
95
|
onRightClick?: () => void;
|
package/out/components/icon.luau
CHANGED
|
@@ -33,7 +33,8 @@ local Notification = TS.import(script, script.Parent, "notification").Notificati
|
|
|
33
33
|
* both states, or `{ deselected: T; selected: T }` to animate between them.
|
|
34
34
|
|
|
35
35
|
]]
|
|
36
|
-
local ANIMATEABLE = { "backgroundColor", "backgroundTransparency", "imageColor", "imageTransparency", "textTransparency" }
|
|
36
|
+
local ANIMATEABLE = { "backgroundColor", "backgroundTransparency", "imageColor", "imageTransparency", "textColor", "textTransparency" }
|
|
37
|
+
local FLASH_DURATION = 0.35
|
|
37
38
|
--* Icon select/deselect state.
|
|
38
39
|
--[[
|
|
39
40
|
*
|
|
@@ -61,6 +62,9 @@ local function Icon(componentProps)
|
|
|
61
62
|
local location = useLocation()
|
|
62
63
|
local id = useId()
|
|
63
64
|
local currentState, setState = useState(componentProps.forcedState or "deselected")
|
|
65
|
+
--* Transiently lights the icon up on a single click when not in toggle mode.
|
|
66
|
+
local flash, setFlash = useState(false)
|
|
67
|
+
local flashTimer = useRef()
|
|
64
68
|
local hovered, setHovered = useState(false)
|
|
65
69
|
local hoverLift, hoverLiftMotion = useMotion(0)
|
|
66
70
|
local dropdownAnimating, setAnimationState = useState(false)
|
|
@@ -76,12 +80,13 @@ local function Icon(componentProps)
|
|
|
76
80
|
_object[_k] = _v
|
|
77
81
|
end
|
|
78
82
|
local sizing = _object
|
|
83
|
+
local animateState = if flash then "selected" else currentState
|
|
79
84
|
local _object_1 = table.clone(stylesheet.icon)
|
|
80
85
|
setmetatable(_object_1, nil)
|
|
81
86
|
for _k, _v in componentProps do
|
|
82
87
|
_object_1[_k] = _v
|
|
83
88
|
end
|
|
84
|
-
local animatedProps = useAnimateableProps(
|
|
89
|
+
local animatedProps = useAnimateableProps(animateState, _object_1, unpack(ANIMATEABLE))
|
|
85
90
|
local _object_2 = table.clone(stylesheet.icon)
|
|
86
91
|
setmetatable(_object_2, nil)
|
|
87
92
|
for _k, _v in (style or {}) do
|
|
@@ -140,7 +145,7 @@ local function Icon(componentProps)
|
|
|
140
145
|
if props.static then
|
|
141
146
|
return nil
|
|
142
147
|
end
|
|
143
|
-
if
|
|
148
|
+
if props.toggle then
|
|
144
149
|
setState(if currentState == "deselected" then "selected" else "deselected")
|
|
145
150
|
end
|
|
146
151
|
end)
|
|
@@ -227,6 +232,11 @@ local function Icon(componentProps)
|
|
|
227
232
|
local _vector2_1 = Vector2.new(0, if includeContents then contentSize.Y else 0)
|
|
228
233
|
location.registerChild(id, _vector2 + _vector2_1)
|
|
229
234
|
end, { currentState, contentSize.Y, dropdownAnimating, iconSize })
|
|
235
|
+
useUnmountEffect(function()
|
|
236
|
+
if flashTimer.current then
|
|
237
|
+
task.cancel(flashTimer.current)
|
|
238
|
+
end
|
|
239
|
+
end)
|
|
230
240
|
useUnmountEffect(function()
|
|
231
241
|
if props.static then
|
|
232
242
|
return nil
|
|
@@ -269,8 +279,17 @@ local function Icon(componentProps)
|
|
|
269
279
|
if props.static then
|
|
270
280
|
return nil
|
|
271
281
|
end
|
|
272
|
-
if
|
|
282
|
+
if props.toggle then
|
|
273
283
|
setState(if currentState == "deselected" then "selected" else "deselected")
|
|
284
|
+
else
|
|
285
|
+
if flashTimer.current then
|
|
286
|
+
task.cancel(flashTimer.current)
|
|
287
|
+
end
|
|
288
|
+
setFlash(true)
|
|
289
|
+
flashTimer.current = task.delay(FLASH_DURATION, function()
|
|
290
|
+
flashTimer.current = nil
|
|
291
|
+
setFlash(false)
|
|
292
|
+
end)
|
|
274
293
|
end
|
|
275
294
|
props.onClick()
|
|
276
295
|
local soundId = stateful(props.leftClickSound, currentState)
|
|
@@ -333,7 +352,7 @@ local function Icon(componentProps)
|
|
|
333
352
|
})), currentText ~= nil and currentText ~= "" and (React.createElement("textlabel", {
|
|
334
353
|
FontFace = stateful(props.fontFace, currentState),
|
|
335
354
|
TextSize = stateful(props.textSize, currentState),
|
|
336
|
-
TextColor3 =
|
|
355
|
+
TextColor3 = animatedProps.textColor,
|
|
337
356
|
TextWrapped = false,
|
|
338
357
|
Size = UDim2.fromOffset(textBounds.X, 0),
|
|
339
358
|
AutomaticSize = Enum.AutomaticSize.Y,
|
package/out/style.luau
CHANGED
|
@@ -49,7 +49,7 @@ local DefaultStylesheet = {
|
|
|
49
49
|
text = "",
|
|
50
50
|
defaultState = "deselected",
|
|
51
51
|
forcedState = "deselected",
|
|
52
|
-
|
|
52
|
+
toggle = false,
|
|
53
53
|
static = false,
|
|
54
54
|
disabled = false,
|
|
55
55
|
toggleKey = Enum.KeyCode.None,
|
|
@@ -87,7 +87,7 @@ local DefaultStylesheet = {
|
|
|
87
87
|
provider = {
|
|
88
88
|
paddingLeft = 8,
|
|
89
89
|
paddingRight = 12,
|
|
90
|
-
paddingTop =
|
|
90
|
+
paddingTop = 12,
|
|
91
91
|
paddingBottom = 0,
|
|
92
92
|
iconSpacing = 12,
|
|
93
93
|
backgroundTransparency = 1,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nrbx/topbar-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"main": "out/init.luau",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "rbxtsc",
|
|
@@ -26,16 +26,16 @@
|
|
|
26
26
|
],
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
29
|
-
"url": "git+https://github.com/
|
|
29
|
+
"url": "git+https://github.com/nrbx-ts/rbxts-topbar-components.git"
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@biomejs/biome": "^2.5.
|
|
35
|
+
"@biomejs/biome": "^2.5.8",
|
|
36
36
|
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
37
37
|
"@rbxts/react": "^17.3.7-ts.2",
|
|
38
|
-
"@rbxts/types": "^1.0.
|
|
38
|
+
"@rbxts/types": "^1.0.943",
|
|
39
39
|
"roblox-ts": "^3.0.0",
|
|
40
40
|
"typescript": "^6.0.3"
|
|
41
41
|
},
|