Skip to content

Commit 8296a88

Browse files
authored
Merge pull request #5 from PepeElToro41/dev
UI Labs v1.1.0
2 parents 6246bcf + e5687e8 commit 8296a88

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2083
-1467
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@rbxts/colour-utils": "^1.4.1",
2828
"@rbxts/flipper": "^2.0.1",
2929
"@rbxts/immut": "^0.4.4-ts.0",
30+
"@rbxts/janitor": "^1.15.7-ts.0",
3031
"@rbxts/pretty-react-hooks": "^0.4.2",
3132
"@rbxts/react": "^0.3.3",
3233
"@rbxts/react-reflex": "^0.3.4",
@@ -35,6 +36,6 @@
3536
"@rbxts/services": "^1.5.1",
3637
"@rbxts/sift": "^0.0.6",
3738
"@rbxts/signal": "^1.1.1",
38-
"@rbxts/ui-labs": "^2.0.0"
39+
"@rbxts/ui-labs": "2.1.0-test1"
3940
}
4041
}

src/Context/DescriptionContext.tsx

+17-17
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import React, { PropsWithChildren, useCallback, useContext, useEffect, useMemo,
33
import { Array } from "@rbxts/sift";
44

55
interface DescriptionInfo {
6-
Name: string;
6+
Identifier: unknown;
77
Description: string;
88
}
99

1010
interface DescriptionContext {
1111
ActiveDescription: string | undefined;
12-
SetDescription: (name: string, description: string) => void;
13-
RemoveDescription: (name: string) => void;
12+
SetDescription: (identifier: unknown, description: string) => void;
13+
RemoveDescription: (identifier: unknown) => void;
1414
}
1515

1616
const DescriptionContext = React.createContext({} as DescriptionContext);
@@ -22,33 +22,33 @@ export function DescriptionProvider(props: DescriptionProviderProps) {
2222
const [currentDescription, setCurrentDescription] = useState<DescriptionInfo>();
2323
const [descriptionVisible, setDescriptionVisible] = useState(false);
2424

25-
const descriptionName = currentDescription && currentDescription.Name;
25+
const descriptionName = currentDescription && currentDescription.Identifier;
2626

27-
const SetDescription = useCallback((name: string, description: string) => {
27+
const SetDescription = useCallback((identifier: unknown, description: string) => {
2828
setDescriptionArray((oldArray) => {
29-
const found = oldArray.find((entry) => entry.Name === name) !== undefined;
29+
const found = oldArray.find((entry) => entry.Identifier === identifier) !== undefined;
3030
if (found) {
3131
//editing existing entry
3232
return Array.map(oldArray, (entry) => {
33-
if (entry.Name === name) {
34-
return { Name: name, Description: description };
33+
if (entry.Identifier === identifier) {
34+
return { Identifier: identifier, Description: description };
3535
} else {
3636
return entry;
3737
}
3838
});
3939
} else {
4040
//adding new entry
41-
return Array.insert(oldArray, 1, { Name: name, Description: description });
41+
return Array.insert(oldArray, 1, { Identifier: identifier, Description: description });
4242
}
4343
});
4444
}, []);
45-
const RemoveDescription = useCallback((name: string) => {
45+
const RemoveDescription = useCallback((identifier: unknown) => {
4646
setDescriptionArray((oldArray) => {
47-
const found = oldArray.find((entry) => entry.Name === name) !== undefined;
47+
const found = oldArray.find((entry) => entry.Identifier === identifier) !== undefined;
4848
if (!found) return oldArray;
4949

5050
return Array.filter(oldArray, (entry) => {
51-
return entry.Name !== name;
51+
return entry.Identifier !== identifier;
5252
});
5353
});
5454
}, []);
@@ -68,7 +68,7 @@ export function DescriptionProvider(props: DescriptionProviderProps) {
6868
setDescriptionVisible(true);
6969
},
7070
[descriptionName],
71-
{ wait: 0.5 },
71+
{ wait: 0.7 },
7272
);
7373

7474
const contextValue = useMemo(() => {
@@ -101,17 +101,17 @@ export function useDescriptionControl() {
101101
return controls;
102102
}
103103

104-
export function useDescriptionDisplay(uid: string) {
104+
export function useDescriptionDisplay(identifier: unknown) {
105105
const context = useContext(DescriptionContext);
106106

107-
const DisplayDescription = useCallback((description: string) => context.SetDescription(uid, description), [uid]);
108-
const RemoveDescription = useCallback(() => context.RemoveDescription(uid), [uid]);
107+
const DisplayDescription = useCallback((description: string) => context.SetDescription(identifier, description), [identifier]);
108+
const RemoveDescription = useCallback(() => context.RemoveDescription(identifier), [identifier]);
109109

110110
const values = useMemo(() => {
111111
return { DisplayDescription, RemoveDescription };
112112
}, []);
113113

114-
useUnmountEffect(() => context.RemoveDescription(uid));
114+
useUnmountEffect(() => context.RemoveDescription(identifier));
115115

116116
return values;
117117
}

src/Hooks/Reflex/Control/ModuleRequire/StorybookLoader.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ export class StorybookLoader {
1717
return this.StorybookResult;
1818
}
1919
Init() {
20-
const reloaderResult = HotReloader.require(this.Module);
21-
this.HotReloader = reloaderResult.Reloader;
20+
const reloader = new HotReloader(this.Module);
21+
this.HotReloader = reloader;
2222

23-
this.OnReloadPromise(reloaderResult.Result);
24-
this.HotReloaderConnection = reloaderResult.Reloader.OnReloadStarted.Connect((result) => {
23+
this.OnReloadPromise(reloader.Reload());
24+
reloader.BindToReload((enviroment) => {});
25+
26+
this.HotReloaderConnection = reloader.OnReloadStarted.Connect((result) => {
2527
this.OnReloadPromise(result);
2628
});
2729
}

src/Hooks/Utils/AppHolder.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { useSelector } from "@rbxts/react-reflex";
22
import { useCallback } from "@rbxts/react";
33
import { selectHolder } from "Reflex/Interface";
44

5-
//this hook gives you a function that converts AbsolutePosition to relative position
6-
//based on the main frame that holds the entire plugin UI
7-
//this is needed because in the story plugin where I visualize UI-labs the UI is usually not in the at the root frame
5+
/*
6+
this hook gives you a function that converts AbsolutePosition to relative position
7+
based on the main frame that holds the entire plugin UI
8+
this is needed because when I visualize the plugin in a story the main frame is not at [0, 0]
9+
*/
810
export function usePosition() {
911
const holder = useSelector(selectHolder);
1012

src/Hooks/Utils/Toggler.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useState, useCallback, useMemo } from "@rbxts/react";
2+
import { CreateTuple } from "Utils/MiscUtils";
23

34
export function useToggler(initial: boolean) {
45
const [enabled, setEnabled] = useState(initial);
@@ -21,5 +22,5 @@ export function useToggler(initial: boolean) {
2122
set: setEnabled,
2223
};
2324
}, []);
24-
return $tuple(enabled, api);
25+
return CreateTuple(enabled, api);
2526
}

src/Plugin/Configs.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ const Configs = {
1313
"StarterGui",
1414
"StarterPlayer",
1515
]),
16+
GlobalInjectionKey: "__hotreload_env_global_injection__", //the longer the better
1617

1718
Version: {
1819
Mayor: 1,
19-
Minor: 0,
20-
Fix: 1,
20+
Minor: 1,
21+
Fix: 0,
2122
},
2223

2324
Extensions: {

src/Reflex/Overlay.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React from "@rbxts/react";
44
interface OverlayEntry {
55
Key: string;
66
Element: React.Element;
7+
Identifier?: unknown;
78
}
89
interface HintEntry {
910
Id: string;
@@ -23,15 +24,26 @@ const initialState: OverlayState = {
2324
export const selectOverlay = (state: RootState) => state.overlay.overlay;
2425

2526
export const OverlayProducer = createProducer(initialState, {
26-
setOverlay: (state, key: string, element: React.Element) => {
27+
setOverlay: (state, key: string, element: React.Element, identifier?: unknown) => {
2728
return {
2829
...state,
2930
overlay: {
3031
Key: key,
3132
Element: element,
33+
Identifier: identifier,
3234
},
3335
};
3436
},
37+
resetIdentifiedOverlay: (state, identifier: unknown) => {
38+
if (!state.overlay) return state;
39+
if (state.overlay.Identifier !== identifier) {
40+
return state;
41+
}
42+
return {
43+
...state,
44+
overlay: undefined,
45+
};
46+
},
3547
resetOverlay: (state) => {
3648
return {
3749
...state,

src/Reflex/StoryPreview/StoryMount.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ declare global {
1515
OnWidget: boolean;
1616
OnViewport: boolean;
1717
Visible: boolean;
18+
AutoReload: boolean;
1819

1920
Zoom: number;
2021
Offset: Vector2;
@@ -30,6 +31,7 @@ const DefaultEntry = {
3031
Visible: true,
3132
OnWidget: false,
3233
OnViewport: false,
34+
AutoReload: true,
3335
} satisfies Partial<PreviewEntry>;
3436

3537
interface StoryMountState {
@@ -64,7 +66,7 @@ export const selectMountAmount = (module: ModuleScript) => (state: RootState) =>
6466
};
6567

6668
function CreateNewEntry(module: ModuleScript, order: number) {
67-
const uid = HttpService.GenerateGUID();
69+
const uid = HttpService.GenerateGUID(false);
6870
const newEntry: PreviewEntry = {
6971
...DefaultEntry,
7072
UID: uid,
@@ -149,6 +151,12 @@ export const StoryMountProducer = createProducer(initialState, {
149151
mountPreviews: FilterEntryMap(state.mountPreviews, (entry) => entry.Key !== key),
150152
};
151153
},
154+
unmountByUID: (state, uid: string) => {
155+
return {
156+
...state,
157+
mountPreviews: FilterEntryMap(state.mountPreviews, (entry) => entry.UID !== uid),
158+
};
159+
},
152160
unmountByModule: (state, module: ModuleScript) => {
153161
return {
154162
...state,

src/Stories/ControlsTest.story.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import React from "@rbxts/react";
22
import ReactRoblox from "@rbxts/react-roblox";
33
import { CreateReactStory } from "@rbxts/ui-labs";
4+
import { Enviroment } from "@rbxts/ui-labs";
45

56
const controls = {
67
Color: Color3.fromRGB(25555, 0, 0),
78
Number: 10,
89
};
910

11+
const RANDOMNUMB = BrickColor.random();
12+
1013
const story = CreateReactStory({ controls: controls, react: React, reactRoblox: ReactRoblox }, (props) => {
11-
return <frame BackgroundColor3={props.controls.Color}></frame>;
14+
return <frame BackgroundColor3={RANDOMNUMB.Color} Size={UDim2.fromOffset(200, 200)}></frame>;
1215
});
1316
export = story;

src/Stories/EnviromentTest.story.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from "@rbxts/react";
2+
import ReactRoblox from "@rbxts/react-roblox";
3+
import { CreateReactStory, Enviroment } from "@rbxts/ui-labs";
4+
import Corner from "UI/Styles/Corner";
5+
6+
const controls = {};
7+
8+
const returnStory = CreateReactStory(
9+
{
10+
summary: "",
11+
react: React,
12+
reactRoblox: ReactRoblox,
13+
controls: controls,
14+
},
15+
(props) => {
16+
return (
17+
<frame Size={UDim2.fromOffset(150, 50)}>
18+
<Corner />
19+
<textlabel
20+
Text={"TextSet"}
21+
Size={UDim2.fromScale(1, 1)}
22+
BackgroundTransparency={1}
23+
TextSize={18}
24+
FontFace={Font.fromEnum(Enum.Font.GothamBold)}
25+
/>
26+
</frame>
27+
);
28+
},
29+
);
30+
31+
export = returnStory;

src/Stories/UILabsTheme.story.tsx

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React, { useEffect } from "@rbxts/react";
2+
import { ReflexProvider, useProducer } from "@rbxts/react-reflex";
3+
import ReactRoblox from "@rbxts/react-roblox";
4+
import { ControlGroup, CreateReactStory, InferControls } from "@rbxts/ui-labs";
5+
import { ReturnControls } from "@rbxts/ui-labs/src/ControlTypings/Typing";
6+
import { useTheme } from "Hooks/Reflex/Use/Theme";
7+
import { RootProducer } from "Reflex";
8+
import Themes from "Themes";
9+
import App from "UI/App";
10+
11+
const controls = {};
12+
13+
function Cast<T>(val: unknown): T {
14+
return val as T;
15+
}
16+
17+
function GenerateControls(baseTheme: Theme) {
18+
const generated: ReturnControls = {};
19+
20+
for (const [index, val] of pairs(baseTheme)) {
21+
if (typeIs(val, "table")) {
22+
const indexControls = GenerateControls(Cast<Theme>(val));
23+
generated[index] = ControlGroup(indexControls as any);
24+
continue;
25+
}
26+
generated[index] = Cast<Color3 | number>(val);
27+
}
28+
29+
return generated;
30+
}
31+
32+
function StoryCreate(props: { Controls: InferControls<typeof controls> }) {
33+
const { setTheme } = useProducer<RootProducer>();
34+
35+
useEffect(() => {
36+
setTheme(Cast<Theme>({ ...props.Controls }));
37+
}, [props.Controls]);
38+
39+
return <App></App>;
40+
}
41+
42+
const returnStory = CreateReactStory(
43+
{
44+
summary: "",
45+
react: React,
46+
reactRoblox: ReactRoblox,
47+
controls: GenerateControls(Themes.Dark),
48+
},
49+
(props) => {
50+
return (
51+
<ReflexProvider producer={RootProducer}>
52+
<StoryCreate Controls={props.controls} />
53+
</ReflexProvider>
54+
);
55+
},
56+
);
57+
58+
export = returnStory;

0 commit comments

Comments
 (0)