@nrbx/topbar-components 1.0.11 → 1.1.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/LICENSE.txt +1 -1
- package/README.md +163 -17
- package/out/components/custom-dropdown.d.ts +19 -0
- package/out/components/custom-dropdown.luau +86 -0
- package/out/components/dropdown.d.ts +20 -0
- package/out/components/dropdown.luau +12 -7
- package/out/components/icon.d.ts +68 -3
- package/out/components/icon.luau +99 -21
- package/out/components/notification.d.ts +10 -0
- package/out/components/notification.luau +52 -0
- package/out/components/overflow.d.ts +10 -0
- package/out/components/overflow.luau +62 -0
- package/out/components/provider.d.ts +16 -1
- package/out/components/provider.luau +17 -4
- package/out/components/stylesheet.d.ts +7 -0
- package/out/components/stylesheet.luau +9 -1
- package/out/components/tooltip.d.ts +14 -0
- package/out/components/tooltip.luau +99 -0
- package/out/hooks/use-animateable-props.d.ts +2 -3
- package/out/hooks/use-animateable-props.luau +4 -5
- package/out/hooks/use-toggle-key.d.ts +6 -0
- package/out/hooks/use-toggle-key.luau +29 -0
- package/out/hooks/use-voicechat-enabled.luau +1 -1
- package/out/index.d.ts +5 -0
- package/out/init.luau +15 -0
- package/out/style.d.ts +117 -35
- package/out/style.luau +47 -0
- package/out/utilities/debug.d.ts +0 -4
- package/out/utilities/debug.luau +0 -6
- package/out/utilities/merge.d.ts +1 -2
- package/out/utilities/merge.luau +33 -29
- package/out/utilities/springs.d.ts +4 -0
- package/out/utilities/springs.luau +1 -1
- package/package.json +12 -6
package/LICENSE.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2023 wad4444
|
|
3
|
+
Copyright (c) 2023 ninjaninja140 (forked from wad4444)
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
|
6
6
|
in the Software without restriction, including without limitation the rights
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
**Topbar Components** is a react component package that mimics [*topbar-plus*](https://devforum.roblox.com/t/v3-topbarplus-v300-construct-intuitive-topbar-icons-customise-them-with-themes-dropdowns-captions-labels-and-much-more/1017485) for [Roblox-TS](https://roblox-ts.com), with JSX markup support.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Installation
|
|
19
19
|
|
|
20
20
|
**@nrbx/topbar-components** is available on NPM and can be installed with the following commands:
|
|
21
21
|
|
|
@@ -45,7 +45,7 @@ And this to your `tsconfig.json`
|
|
|
45
45
|
"typeRoots": ["node_modules/@rbxts", "node_modules/@nrbx"],
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
###
|
|
48
|
+
### Quick Start
|
|
49
49
|
|
|
50
50
|
Instantiate `<TopbarProvider />` to be a root of your topbar component tree.
|
|
51
51
|
|
|
@@ -55,7 +55,7 @@ Instantiate `<TopbarProvider />` to be a root of your topbar component tree.
|
|
|
55
55
|
</TopbarProvider>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
####
|
|
58
|
+
#### Positioning icons with dock containers
|
|
59
59
|
|
|
60
60
|
Icons placed directly inside `<TopbarProvider>` default to the left side. Use the dock container components to position icons at the center or right of the bar:
|
|
61
61
|
|
|
@@ -76,16 +76,16 @@ Icons placed directly inside `<TopbarProvider>` default to the left side. Use th
|
|
|
76
76
|
|
|
77
77
|
| Container | Anchor | Purpose |
|
|
78
78
|
|---|---|---|
|
|
79
|
-
| `<LeftDock>` | left edge | Default
|
|
79
|
+
| `<LeftDock>` | left edge | Default - icons flow left-to-right from the left |
|
|
80
80
|
| `<CenterDock>` | center (50%) | Centers icons in the bar |
|
|
81
81
|
| `<RightDock>` | right edge | Right-aligns icons |
|
|
82
82
|
|
|
83
83
|
Each dock container renders its own horizontal list with the configured `iconSpacing` and vertical centering. Center and right docks automatically apply `iconGroupSpacing` for visual separation.
|
|
84
84
|
|
|
85
|
-
####
|
|
85
|
+
#### Icon props: `static` and `disabled`
|
|
86
86
|
|
|
87
|
-
- **`static`**
|
|
88
|
-
- **`disabled`**
|
|
87
|
+
- **`static`** - turns the icon into a non-interactive label (no clicks, no hovers, no state toggling, no sounds)
|
|
88
|
+
- **`disabled`** - dims the icon with a configurable semi-transparent overlay
|
|
89
89
|
|
|
90
90
|
```tsx
|
|
91
91
|
<Icon text="Read Only" static /> {/* label, not clickable */}
|
|
@@ -95,7 +95,7 @@ Each dock container renders its own horizontal list with the configured `iconSpa
|
|
|
95
95
|
|
|
96
96
|
The disabled overlay transparency and color are configurable via the stylesheet `sizing` section.
|
|
97
97
|
|
|
98
|
-
####
|
|
98
|
+
#### Dropdowns
|
|
99
99
|
|
|
100
100
|
You can add a dropdown to an icon by mounting `<Dropdown />` component as it's child.
|
|
101
101
|
Dropdowns & TopbarProvider have a property called `selectionMode`, which lets you specify how many icons can be selected at once.
|
|
@@ -111,7 +111,107 @@ Dropdowns & TopbarProvider have a property called `selectionMode`, which lets yo
|
|
|
111
111
|
|
|
112
112
|
Dropdowns **can be nested.**
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
#### Hover animations
|
|
115
|
+
|
|
116
|
+
Icons can lift upward on hover for a subtle interactive feel. Enable or disable it globally via the stylesheet:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<Stylesheet stylesheet={{
|
|
120
|
+
animation: {
|
|
121
|
+
hoverEnabled: true, // turn hover lift on/off
|
|
122
|
+
hoverLift: 4, // pixels to lift
|
|
123
|
+
},
|
|
124
|
+
}}>
|
|
125
|
+
<TopbarProvider>
|
|
126
|
+
<Icon text="Hover Me" />
|
|
127
|
+
</TopbarProvider>
|
|
128
|
+
</Stylesheet>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Hover lift uses the same spring configuration as state transitions (`animation.stateSpring`).
|
|
132
|
+
|
|
133
|
+
#### Notification badges
|
|
134
|
+
|
|
135
|
+
Add a red notification badge to any icon with the `notificationCount` prop. Counts over 99 display as `99+`. The badge hides automatically when the count is 0.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<Icon text="Inbox" notificationCount={3} />
|
|
139
|
+
<Icon text="Mail" notificationCount={150} /> {/* shows "99+" */}
|
|
140
|
+
<Icon text="Clear" notificationCount={0} /> {/* badge hidden */}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Badge styling (colors, position, corner radius, border) is controlled via `stylesheet.notification`.
|
|
144
|
+
|
|
145
|
+
#### Toggle keys
|
|
146
|
+
|
|
147
|
+
Bind a keyboard key to toggle an icon on/off with the `toggleKey` prop:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<Icon text="Menu" toggleKey={Enum.KeyCode.M} toggleStateOnClick />
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Any `Enum.KeyCode` value works. The key binding only activates while the icon is mounted.
|
|
154
|
+
|
|
155
|
+
#### Tooltips
|
|
156
|
+
|
|
157
|
+
Wrap any element in a `<Tooltip>` to show a hover tooltip after a configurable delay:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
<Tooltip content="Go home" side="bottom" delayMs={500}>
|
|
161
|
+
<Icon imageId="rbxassetid://..." />
|
|
162
|
+
</Tooltip>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
| Prop | Type | Default | Description |
|
|
166
|
+
|---|---|---|---|
|
|
167
|
+
| `content` | `string` | required | Text displayed inside the tooltip |
|
|
168
|
+
| `side` | `"top"` \| `"bottom"` \| `"left"` \| `"right"` | `"top"` | Which side of the child to appear on |
|
|
169
|
+
| `delayMs` | `number` | stylesheet value | Milliseconds before the tooltip appears |
|
|
170
|
+
|
|
171
|
+
Tooltip appearance (colors, font, padding, border) is controlled via `stylesheet.tooltip`.
|
|
172
|
+
|
|
173
|
+
#### Custom Dropdowns
|
|
174
|
+
|
|
175
|
+
Use `<CustomDropdown>` when you need to show rich, arbitrary content in a dropdown panel - not just child `<Icon>` elements:
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
<Icon text="Info" toggleStateOnClick>
|
|
179
|
+
<CustomDropdown width={250} maxHeight={180}>
|
|
180
|
+
<textlabel Text="Custom content here!" />
|
|
181
|
+
<textbutton Text="A button" />
|
|
182
|
+
</CustomDropdown>
|
|
183
|
+
</Icon>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| Prop | Type | Default | Description |
|
|
187
|
+
|---|---|---|---|
|
|
188
|
+
| `visible` | `boolean` | - | Whether the dropdown is open (usually driven by icon state) |
|
|
189
|
+
| `width` | `number` | `200` | Width in pixels |
|
|
190
|
+
| `maxHeight` | `number` | `200` | Max height before scrolling |
|
|
191
|
+
| `position` | `UDim2` | stylesheet value | Position relative to the parent icon |
|
|
192
|
+
|
|
193
|
+
Appearance is controlled via `stylesheet.customDropdown`.
|
|
194
|
+
|
|
195
|
+
#### Overflow handler
|
|
196
|
+
|
|
197
|
+
When you have many icons in a dock, wrap them in `<Overflow>` to automatically collapse extras into a "more" (⋯) dropdown:
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
<LeftDock>
|
|
201
|
+
<Overflow>
|
|
202
|
+
<Icon text="Home" />
|
|
203
|
+
<Icon text="Settings" />
|
|
204
|
+
<Icon text="Profile" />
|
|
205
|
+
<Icon text="Messages" />
|
|
206
|
+
<Icon text="Help" />
|
|
207
|
+
{/* ... many more ... */}
|
|
208
|
+
</Overflow>
|
|
209
|
+
</LeftDock>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Based on TopbarPlus v3's overflow handler.
|
|
213
|
+
|
|
214
|
+
### Stylesheets
|
|
115
215
|
|
|
116
216
|
You can use stylesheets to override default properties of all components within.
|
|
117
217
|
Stylesheets are partial, and work like patches to already established default properties within the package:
|
|
@@ -144,7 +244,7 @@ The stylesheet exposes the following sections for full control:
|
|
|
144
244
|
|
|
145
245
|
```tsx
|
|
146
246
|
<Stylesheet stylesheet={{
|
|
147
|
-
//
|
|
247
|
+
// Icon defaults (all IconProps)
|
|
148
248
|
icon: {
|
|
149
249
|
textSize: 20,
|
|
150
250
|
textColor: { selected: Color3.fromRGB(57, 60, 65), deselected: Color3.fromRGB(255, 255, 255) },
|
|
@@ -157,7 +257,7 @@ The stylesheet exposes the following sections for full control:
|
|
|
157
257
|
// ... all other IconProps
|
|
158
258
|
},
|
|
159
259
|
|
|
160
|
-
//
|
|
260
|
+
// Dropdown defaults (all DropdownProps)
|
|
161
261
|
dropdown: {
|
|
162
262
|
maxWidth: 300,
|
|
163
263
|
minWidth: 200,
|
|
@@ -168,7 +268,7 @@ The stylesheet exposes the following sections for full control:
|
|
|
168
268
|
// ... all other DropdownProps
|
|
169
269
|
},
|
|
170
270
|
|
|
171
|
-
//
|
|
271
|
+
// Provider frame
|
|
172
272
|
provider: {
|
|
173
273
|
paddingLeft: 8, paddingRight: 12,
|
|
174
274
|
paddingTop: 11, paddingBottom: 0,
|
|
@@ -181,12 +281,15 @@ The stylesheet exposes the following sections for full control:
|
|
|
181
281
|
forceFrameHeight: undefined, // override auto height (e.g. 55)
|
|
182
282
|
},
|
|
183
283
|
|
|
184
|
-
//
|
|
284
|
+
// Icon internal sizing
|
|
185
285
|
sizing: {
|
|
186
|
-
iconHeight: undefined,
|
|
286
|
+
iconHeight: undefined, // explicit override
|
|
287
|
+
iconWidth: undefined, // explicit override (auto-fits when undefined/0)
|
|
187
288
|
imagePadding: 6,
|
|
188
289
|
labelPadding: 6,
|
|
189
290
|
imageToTextSpacing: 6,
|
|
291
|
+
contentPaddingX: 6, // horizontal pad from button edge to content
|
|
292
|
+
contentPaddingY: 6, // vertical pad from button edge to content
|
|
190
293
|
textMeasurementWidth: 99999,
|
|
191
294
|
minLabelWidthPadding: 12,
|
|
192
295
|
buttonLabelHeightFraction: 0.8,
|
|
@@ -194,7 +297,7 @@ The stylesheet exposes the following sections for full control:
|
|
|
194
297
|
disabledOverlayColor: new Color3(0, 0, 0),
|
|
195
298
|
},
|
|
196
299
|
|
|
197
|
-
//
|
|
300
|
+
// Dropdown surface theme
|
|
198
301
|
dropdownTheme: {
|
|
199
302
|
backgroundColor: new Color3(1, 1, 1),
|
|
200
303
|
backgroundTransparency: 0,
|
|
@@ -204,17 +307,60 @@ The stylesheet exposes the following sections for full control:
|
|
|
204
307
|
position: UDim2.fromScale(0, 1),
|
|
205
308
|
},
|
|
206
309
|
|
|
207
|
-
//
|
|
310
|
+
// Animation
|
|
208
311
|
animation: {
|
|
209
312
|
dropdownTransitionSpeed: 10,
|
|
210
313
|
stateSpring: { tension: 400 },
|
|
314
|
+
hoverEnabled: true, // whether icons lift on hover
|
|
315
|
+
hoverLift: 4, // pixels to lift
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
// Notification badge
|
|
319
|
+
notification: {
|
|
320
|
+
backgroundColor: Color3.fromRGB(255, 59, 48),
|
|
321
|
+
backgroundTransparency: 0,
|
|
322
|
+
textColor: new Color3(1, 1, 1),
|
|
323
|
+
textSize: 12,
|
|
324
|
+
fontFace: new Font("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Bold),
|
|
325
|
+
position: new UDim2(0.5, 4, 0, -4),
|
|
326
|
+
size: new UDim2(0, 18, 0, 18),
|
|
327
|
+
cornerRadius: new UDim(1, 0),
|
|
328
|
+
borderColor: new Color3(1, 1, 1),
|
|
329
|
+
borderTransparency: 0,
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
// Tooltip
|
|
333
|
+
tooltip: {
|
|
334
|
+
backgroundColor: new Color3(0.1, 0.1, 0.1),
|
|
335
|
+
backgroundTransparency: 0.2,
|
|
336
|
+
textColor: new Color3(1, 1, 1),
|
|
337
|
+
textSize: 14,
|
|
338
|
+
fontFace: new Font("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Medium),
|
|
339
|
+
cornerRadius: new UDim(0, 4),
|
|
340
|
+
borderColor: new Color3(0.4, 0.4, 0.4),
|
|
341
|
+
borderTransparency: 0,
|
|
342
|
+
borderSize: 1,
|
|
343
|
+
paddingX: 8,
|
|
344
|
+
paddingY: 4,
|
|
345
|
+
delayMs: 500,
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
// Custom dropdown
|
|
349
|
+
customDropdown: {
|
|
350
|
+
backgroundColor: new Color3(1, 1, 1),
|
|
351
|
+
backgroundTransparency: 0,
|
|
352
|
+
cornerRadius: new UDim(0, 6),
|
|
353
|
+
borderSize: 0,
|
|
354
|
+
borderColor: new Color3(0, 0, 0),
|
|
355
|
+
borderTransparency: 1,
|
|
356
|
+
position: UDim2.fromScale(0, 1),
|
|
211
357
|
},
|
|
212
358
|
}}>
|
|
213
359
|
{/* children */}
|
|
214
360
|
</Stylesheet>
|
|
215
361
|
```
|
|
216
362
|
|
|
217
|
-
###
|
|
363
|
+
### License
|
|
218
364
|
|
|
219
365
|
Package is licensed under the MIT License.
|
|
220
366
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from '@rbxts/react';
|
|
2
|
+
interface CustomDropdownProps extends React.PropsWithChildren {
|
|
3
|
+
/** Whether the dropdown is visible. Typically driven by parent icon state. */
|
|
4
|
+
visible: boolean;
|
|
5
|
+
/** Width of the dropdown in pixels. */
|
|
6
|
+
width?: number;
|
|
7
|
+
/** Maximum height before scrolling. */
|
|
8
|
+
maxHeight?: number;
|
|
9
|
+
/** Position relative to the parent icon. */
|
|
10
|
+
position?: UDim2;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A dropdown panel for arbitrary custom content (not just child icons).
|
|
14
|
+
*
|
|
15
|
+
* Use this when you need rich UI inside a dropdown — forms, text, images —
|
|
16
|
+
* rather than a list of `<Icon>` children. Animated open/closed with a spring.
|
|
17
|
+
*/
|
|
18
|
+
export declare function CustomDropdown({ visible, width, maxHeight, position, children }: CustomDropdownProps): React.JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _pretty_react_hooks = TS.import(script, TS.getModule(script, "@rbxts", "pretty-react-hooks").out)
|
|
4
|
+
local mapBinding = _pretty_react_hooks.mapBinding
|
|
5
|
+
local useMotion = _pretty_react_hooks.useMotion
|
|
6
|
+
local useMountEffect = _pretty_react_hooks.useMountEffect
|
|
7
|
+
local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
|
|
8
|
+
local React = _react
|
|
9
|
+
local useBinding = _react.useBinding
|
|
10
|
+
local useRef = _react.useRef
|
|
11
|
+
local useStylesheet = TS.import(script, script.Parent.Parent, "context").useStylesheet
|
|
12
|
+
--[[
|
|
13
|
+
*
|
|
14
|
+
* A dropdown panel for arbitrary custom content (not just child icons).
|
|
15
|
+
*
|
|
16
|
+
* Use this when you need rich UI inside a dropdown — forms, text, images —
|
|
17
|
+
* rather than a list of `<Icon>` children. Animated open/closed with a spring.
|
|
18
|
+
|
|
19
|
+
]]
|
|
20
|
+
local function CustomDropdown(_param)
|
|
21
|
+
local visible = _param.visible
|
|
22
|
+
local width = _param.width
|
|
23
|
+
if width == nil then
|
|
24
|
+
width = 200
|
|
25
|
+
end
|
|
26
|
+
local maxHeight = _param.maxHeight
|
|
27
|
+
if maxHeight == nil then
|
|
28
|
+
maxHeight = 200
|
|
29
|
+
end
|
|
30
|
+
local position = _param.position
|
|
31
|
+
local children = _param.children
|
|
32
|
+
local stylesheet = useStylesheet()
|
|
33
|
+
local theme = stylesheet.customDropdown
|
|
34
|
+
local animation = stylesheet.animation
|
|
35
|
+
local transition, transitionMotion = useMotion(if visible then 1 else 0)
|
|
36
|
+
local contentSize, setContentSize = useBinding(Vector2.zero)
|
|
37
|
+
local frameRef = useRef()
|
|
38
|
+
React.useEffect(function()
|
|
39
|
+
transitionMotion:spring(if visible then 1 else 0, {
|
|
40
|
+
tension = animation.dropdownTransitionSpeed * 15,
|
|
41
|
+
friction = 26,
|
|
42
|
+
})
|
|
43
|
+
end, { visible })
|
|
44
|
+
useMountEffect(function()
|
|
45
|
+
local frame = frameRef.current
|
|
46
|
+
if not frame then
|
|
47
|
+
return nil
|
|
48
|
+
end
|
|
49
|
+
setContentSize(frame.AbsoluteCanvasSize)
|
|
50
|
+
local conn = frame:GetPropertyChangedSignal("AbsoluteCanvasSize"):Connect(function()
|
|
51
|
+
setContentSize(frame.AbsoluteCanvasSize)
|
|
52
|
+
end)
|
|
53
|
+
return function()
|
|
54
|
+
return conn:Disconnect()
|
|
55
|
+
end
|
|
56
|
+
end)
|
|
57
|
+
local pos = position or theme.position
|
|
58
|
+
return React.createElement("scrollingframe", {
|
|
59
|
+
ref = frameRef,
|
|
60
|
+
ClipsDescendants = true,
|
|
61
|
+
Size = mapBinding(transition, function(t)
|
|
62
|
+
return UDim2.fromOffset(width, t * math.min(contentSize:getValue().Y, maxHeight))
|
|
63
|
+
end),
|
|
64
|
+
BorderSizePixel = theme.borderSize,
|
|
65
|
+
BorderColor3 = theme.borderColor,
|
|
66
|
+
BackgroundColor3 = theme.backgroundColor,
|
|
67
|
+
BackgroundTransparency = theme.backgroundTransparency,
|
|
68
|
+
Position = pos,
|
|
69
|
+
CanvasSize = UDim2.fromOffset(0, contentSize:getValue().Y),
|
|
70
|
+
AutomaticCanvasSize = Enum.AutomaticSize.Y,
|
|
71
|
+
ScrollBarThickness = 5,
|
|
72
|
+
ScrollBarImageColor3 = Color3.new(1, 1, 1),
|
|
73
|
+
ScrollBarImageTransparency = 0.8,
|
|
74
|
+
ScrollingEnabled = false,
|
|
75
|
+
ZIndex = 30,
|
|
76
|
+
}, React.createElement("uicorner", {
|
|
77
|
+
CornerRadius = theme.cornerRadius,
|
|
78
|
+
}), React.createElement("uistroke", {
|
|
79
|
+
Color = theme.borderColor,
|
|
80
|
+
Transparency = theme.borderTransparency,
|
|
81
|
+
Thickness = theme.borderSize,
|
|
82
|
+
}), children)
|
|
83
|
+
end
|
|
84
|
+
return {
|
|
85
|
+
CustomDropdown = CustomDropdown,
|
|
86
|
+
}
|
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
import React from '@rbxts/react';
|
|
2
2
|
import type { SelectionMode } from './provider';
|
|
3
|
+
/** Properties accepted by {@link Dropdown}. */
|
|
3
4
|
export interface DropdownProps extends React.PropsWithChildren {
|
|
5
|
+
/** Minimum width of the dropdown in pixels. */
|
|
4
6
|
minWidth?: number;
|
|
7
|
+
/** Maximum height before the dropdown becomes scrollable. */
|
|
5
8
|
maxHeight?: number;
|
|
9
|
+
/** Maximum width of the dropdown in pixels. */
|
|
6
10
|
maxWidth?: number;
|
|
11
|
+
/** Vertical padding between child icons. */
|
|
7
12
|
padding?: UDim;
|
|
13
|
+
/** Fixed height applied to child icons inside this dropdown. */
|
|
8
14
|
forceHeight?: number;
|
|
15
|
+
/** Corner radius applied to child icons inside this dropdown. */
|
|
9
16
|
iconCornerRadius?: UDim;
|
|
17
|
+
/** Scroll bar thickness in pixels. */
|
|
10
18
|
scrollBarThickness?: number;
|
|
19
|
+
/** Scroll bar transparency (0 = opaque, 1 = invisible). */
|
|
11
20
|
scrollBarTransparency?: number;
|
|
21
|
+
/** Image for the scroll bar top cap. */
|
|
12
22
|
topImage?: string;
|
|
23
|
+
/** Image for the scroll bar bottom cap. */
|
|
13
24
|
bottomImage?: string;
|
|
25
|
+
/** Image for the scroll bar middle segment. */
|
|
14
26
|
midImage?: string;
|
|
27
|
+
/** Color applied to the scroll bar images. */
|
|
15
28
|
scrollBarImageColor?: Color3;
|
|
29
|
+
/** Selection mode: `Single` deselects others, `Multiple` allows many. */
|
|
16
30
|
selectionMode?: SelectionMode;
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* A dropdown menu that appears below its parent icon.
|
|
34
|
+
*
|
|
35
|
+
* Child `<Icon>` components placed inside automatically register and size
|
|
36
|
+
* themselves. The dropdown animates open/closed with a spring transition.
|
|
37
|
+
*/
|
|
18
38
|
export declare function Dropdown(componentProps: DropdownProps): React.JSX.Element;
|
|
@@ -13,6 +13,15 @@ local _context = TS.import(script, script.Parent.Parent, "context")
|
|
|
13
13
|
local LocationContext = _context.LocationContext
|
|
14
14
|
local useLocation = _context.useLocation
|
|
15
15
|
local useStylesheet = _context.useStylesheet
|
|
16
|
+
--* Properties accepted by {@link Dropdown}.
|
|
17
|
+
--[[
|
|
18
|
+
*
|
|
19
|
+
* A dropdown menu that appears below its parent icon.
|
|
20
|
+
*
|
|
21
|
+
* Child `<Icon>` components placed inside automatically register and size
|
|
22
|
+
* themselves. The dropdown animates open/closed with a spring transition.
|
|
23
|
+
|
|
24
|
+
]]
|
|
16
25
|
local function Dropdown(componentProps)
|
|
17
26
|
local location = useLocation()
|
|
18
27
|
local fullStylesheet = useStylesheet()
|
|
@@ -43,8 +52,9 @@ local function Dropdown(componentProps)
|
|
|
43
52
|
end, { contents, maxWidth, minWidth, stylesheet.padding.Offset })
|
|
44
53
|
useEffect(function()
|
|
45
54
|
location.setAnimationState(true)
|
|
46
|
-
transitionMotion:
|
|
47
|
-
|
|
55
|
+
transitionMotion:spring(if location.isVisible then 1 else 0, {
|
|
56
|
+
tension = fullStylesheet.animation.dropdownTransitionSpeed * 15,
|
|
57
|
+
friction = 26,
|
|
48
58
|
})
|
|
49
59
|
end, { location.isVisible })
|
|
50
60
|
useMountEffect(function()
|
|
@@ -170,20 +180,15 @@ local function Dropdown(componentProps)
|
|
|
170
180
|
MidImage = props.midImage,
|
|
171
181
|
TopImage = props.topImage,
|
|
172
182
|
BottomImage = props.bottomImage,
|
|
173
|
-
key = "Dropdown",
|
|
174
183
|
}, React.createElement("uicorner", {
|
|
175
|
-
key = "DropdownCorner",
|
|
176
184
|
CornerRadius = fullStylesheet.dropdownTheme.cornerRadius,
|
|
177
185
|
}), React.createElement("uistroke", {
|
|
178
|
-
key = "DropdownStroke",
|
|
179
186
|
Thickness = fullStylesheet.dropdownTheme.borderSize,
|
|
180
187
|
Color = fullStylesheet.dropdownTheme.borderColor,
|
|
181
188
|
Transparency = fullStylesheet.dropdownTheme.borderTransparency,
|
|
182
189
|
}), props.children, isNested and React.createElement("uipadding", {
|
|
183
|
-
key = "UIPadding",
|
|
184
190
|
PaddingTop = stylesheet.padding,
|
|
185
191
|
}), React.createElement("uilistlayout", {
|
|
186
|
-
key = "UIListLayout",
|
|
187
192
|
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
188
193
|
Padding = stylesheet.padding,
|
|
189
194
|
})))
|
package/out/components/icon.d.ts
CHANGED
|
@@ -1,47 +1,112 @@
|
|
|
1
1
|
import React from '@rbxts/react';
|
|
2
2
|
import { type Stylesheet } from '../style';
|
|
3
|
+
/**
|
|
4
|
+
* Properties accepted by {@link Icon}.
|
|
5
|
+
*
|
|
6
|
+
* Most visual props accept a `StateDependent<T>` — either a single value for
|
|
7
|
+
* both states, or `{ deselected: T; selected: T }` to animate between them.
|
|
8
|
+
*/
|
|
3
9
|
export interface IconProps extends React.PropsWithChildren {
|
|
10
|
+
/** Background transparency of the button. Animated on state change. */
|
|
4
11
|
backgroundTransparency?: StateDependent<number>;
|
|
12
|
+
/** Background color of the button. Animated on state change. */
|
|
5
13
|
backgroundColor?: StateDependent<Color3>;
|
|
14
|
+
/** Asset ID or full asset string for the icon image. */
|
|
6
15
|
imageId?: StateDependent<string>;
|
|
16
|
+
/** Color applied to the icon image. Animated on state change. */
|
|
7
17
|
imageColor?: StateDependent<Color3>;
|
|
18
|
+
/** Color applied to the label text. */
|
|
8
19
|
textColor?: StateDependent<Color3>;
|
|
20
|
+
/** Transparency of the icon image. Animated on state change. */
|
|
9
21
|
imageTransparency?: StateDependent<number>;
|
|
22
|
+
/** Layout order used for horizontal sorting in docks. */
|
|
10
23
|
layoutOrder?: StateDependent<number>;
|
|
24
|
+
/** Text displayed next to or instead of the image. */
|
|
11
25
|
text?: StateDependent<string>;
|
|
26
|
+
/** Font size of the label text. */
|
|
12
27
|
textSize?: StateDependent<number>;
|
|
28
|
+
/** Pixel offset added to the computed image size. Negative values shrink the image. */
|
|
13
29
|
imageSizeOffset?: StateDependent<number>;
|
|
30
|
+
/** Offset into the source image to crop from. */
|
|
14
31
|
imageRectOffset?: StateDependent<Vector2>;
|
|
32
|
+
/** Size of the crop region from the source image. */
|
|
15
33
|
imageRectSize?: StateDependent<Vector2>;
|
|
34
|
+
/** Initial state when the icon first mounts. */
|
|
16
35
|
defaultState?: IconState;
|
|
36
|
+
/** Font face used for the label text. */
|
|
17
37
|
fontFace?: StateDependent<Font>;
|
|
38
|
+
/** Override that locks the icon to a specific state. */
|
|
18
39
|
forcedState?: IconState;
|
|
40
|
+
/** Sound played on left click (asset ID or empty for none). */
|
|
19
41
|
leftClickSound?: StateDependent<string>;
|
|
42
|
+
/** Sound played on right click (asset ID or empty for none). */
|
|
20
43
|
rightClickSound?: StateDependent<string>;
|
|
44
|
+
/** Corner radius of the button. */
|
|
21
45
|
cornerRadius?: StateDependent<UDim>;
|
|
46
|
+
/** Stroke transparency of the label text. */
|
|
22
47
|
strokeTransparency?: StateDependent<number>;
|
|
48
|
+
/** Stroke color of the label text. */
|
|
23
49
|
strokeColor?: StateDependent<Color3>;
|
|
50
|
+
/** Stroke thickness of the label text. */
|
|
24
51
|
strokeThickness?: StateDependent<number>;
|
|
52
|
+
/** Horizontal text alignment within the label. */
|
|
25
53
|
textAlignment?: StateDependent<Enum.TextXAlignment>;
|
|
54
|
+
/** Whether the label supports rich text markup. */
|
|
26
55
|
richText?: StateDependent<boolean>;
|
|
56
|
+
/** When `true`, clicking the icon toggles between selected and deselected. */
|
|
27
57
|
toggleStateOnClick?: boolean;
|
|
28
|
-
/** When true
|
|
58
|
+
/** When `true`, the icon ignores all clicks, hover, and state changes. */
|
|
29
59
|
static?: boolean;
|
|
30
|
-
/** When true
|
|
60
|
+
/** When `true`, the icon is dimmed and non-interactive. */
|
|
31
61
|
disabled?: boolean;
|
|
32
|
-
/**
|
|
62
|
+
/** Inline overrides for icon props and sizing values. */
|
|
33
63
|
style?: Partial<IconProps & Stylesheet['sizing']>;
|
|
64
|
+
/** Explicit icon width in pixels. When undefined or `0`, auto-fits to content. */
|
|
65
|
+
iconWidth?: number;
|
|
66
|
+
/** Horizontal padding between the button edge and its content. */
|
|
67
|
+
contentPaddingX?: number;
|
|
68
|
+
/** Vertical padding between the button edge and its content. */
|
|
69
|
+
contentPaddingY?: number;
|
|
70
|
+
/** Gap between the image and the text label. */
|
|
71
|
+
imageToTextSpacing?: number;
|
|
72
|
+
/** KeyCode that toggles the icon when pressed. */
|
|
73
|
+
toggleKey?: Enum.KeyCode;
|
|
74
|
+
/** Shows a red notification badge with this count. Hides when `0` or `undefined`. */
|
|
75
|
+
notificationCount?: number;
|
|
76
|
+
/** Callback fired when the icon becomes selected. */
|
|
34
77
|
selected?: () => void;
|
|
78
|
+
/** Callback fired when the icon becomes deselected. */
|
|
35
79
|
deselected?: () => void;
|
|
80
|
+
/** Callback fired on mouse enter. */
|
|
36
81
|
hover?: () => void;
|
|
82
|
+
/** Callback fired on mouse leave. */
|
|
37
83
|
unhover?: () => void;
|
|
84
|
+
/** Callback fired whenever the state changes (receives the new state). */
|
|
38
85
|
stateChanged?: (state: IconState) => void;
|
|
86
|
+
/** Callback fired on left click (in addition to the built-in toggle). */
|
|
39
87
|
onClick?: () => void;
|
|
88
|
+
/** Callback fired on right click. */
|
|
40
89
|
onRightClick?: () => void;
|
|
90
|
+
/** Function used to play click sounds. Receives the sound asset ID. */
|
|
41
91
|
playSound?: (id: string) => void;
|
|
42
92
|
}
|
|
93
|
+
/** Icon select/deselect state. */
|
|
43
94
|
export type IconState = 'selected' | 'deselected';
|
|
95
|
+
/**
|
|
96
|
+
* A value that can change with icon state.
|
|
97
|
+
* Pass a single value for both states, or `{ deselected, selected }` for
|
|
98
|
+
* separate values that animate on state transitions.
|
|
99
|
+
*/
|
|
44
100
|
export type StateDependent<T> = Record<IconState, T> | T;
|
|
101
|
+
/** Extracts the inner type from a `StateDependent`. */
|
|
45
102
|
export type FromStateDependent<T> = T extends StateDependent<infer U> ? U : T;
|
|
103
|
+
/** Unique numeric identifier for an icon instance. */
|
|
46
104
|
export type IconId = number;
|
|
105
|
+
/**
|
|
106
|
+
* A single icon in the topbar.
|
|
107
|
+
*
|
|
108
|
+
* Supports an image, a text label, state-dependent styling, animated state
|
|
109
|
+
* transitions, hover lift, notification badges, toggle keys, and nested
|
|
110
|
+
* dropdown content.
|
|
111
|
+
*/
|
|
47
112
|
export declare function Icon(componentProps: IconProps): React.JSX.Element;
|