@lattice-ui/switch 0.4.3 → 0.5.0-next.1
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/default.project.json +9 -0
- package/out/Switch/SwitchRoot.luau +15 -1
- package/out/Switch/SwitchThumb.luau +17 -2
- package/package.json +12 -2
- package/src/Switch/SwitchRoot.tsx +87 -0
- package/src/Switch/SwitchThumb.tsx +41 -0
- package/src/Switch/context.ts +6 -0
- package/src/Switch/types.ts +24 -0
- package/src/index.ts +9 -0
|
@@ -4,7 +4,12 @@ local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
|
4
4
|
local React = _core.React
|
|
5
5
|
local Slot = _core.Slot
|
|
6
6
|
local useControllableState = _core.useControllableState
|
|
7
|
+
local _motion = TS.import(script, TS.getModule(script, "@lattice-ui", "motion").out)
|
|
8
|
+
local createToggleResponseRecipe = _motion.createToggleResponseRecipe
|
|
9
|
+
local useResponseMotion = _motion.useResponseMotion
|
|
7
10
|
local SwitchContextProvider = TS.import(script, script.Parent, "context").SwitchContextProvider
|
|
11
|
+
local TRACK_ON_COLOR = Color3.fromRGB(86, 141, 255)
|
|
12
|
+
local TRACK_OFF_COLOR = Color3.fromRGB(66, 73, 91)
|
|
8
13
|
local function SwitchRoot(props)
|
|
9
14
|
local _object = {
|
|
10
15
|
value = props.checked,
|
|
@@ -20,6 +25,14 @@ local function SwitchRoot(props)
|
|
|
20
25
|
local checked = _binding[1]
|
|
21
26
|
local setCheckedState = _binding[2]
|
|
22
27
|
local disabled = props.disabled == true
|
|
28
|
+
local motionRef = useResponseMotion(checked, {
|
|
29
|
+
active = {
|
|
30
|
+
BackgroundColor3 = TRACK_ON_COLOR,
|
|
31
|
+
},
|
|
32
|
+
inactive = {
|
|
33
|
+
BackgroundColor3 = TRACK_OFF_COLOR,
|
|
34
|
+
},
|
|
35
|
+
}, createToggleResponseRecipe())
|
|
23
36
|
local setChecked = React.useCallback(function(nextChecked)
|
|
24
37
|
if disabled then
|
|
25
38
|
return nil
|
|
@@ -52,11 +65,11 @@ local function SwitchRoot(props)
|
|
|
52
65
|
Activated = toggle,
|
|
53
66
|
},
|
|
54
67
|
Selectable = not disabled,
|
|
68
|
+
ref = motionRef,
|
|
55
69
|
}, child)
|
|
56
70
|
end)()) else (React.createElement("textbutton", {
|
|
57
71
|
Active = not disabled,
|
|
58
72
|
AutoButtonColor = false,
|
|
59
|
-
BackgroundColor3 = if checked then Color3.fromRGB(86, 141, 255) else Color3.fromRGB(66, 73, 91),
|
|
60
73
|
BorderSizePixel = 0,
|
|
61
74
|
Event = {
|
|
62
75
|
Activated = toggle,
|
|
@@ -66,6 +79,7 @@ local function SwitchRoot(props)
|
|
|
66
79
|
Text = if checked then "On" else "Off",
|
|
67
80
|
TextColor3 = if disabled then Color3.fromRGB(145, 152, 168) else Color3.fromRGB(240, 244, 252),
|
|
68
81
|
TextSize = 15,
|
|
82
|
+
ref = motionRef,
|
|
69
83
|
}, child)))
|
|
70
84
|
end
|
|
71
85
|
return {
|
|
@@ -3,21 +3,36 @@ local TS = _G[script]
|
|
|
3
3
|
local _core = TS.import(script, TS.getModule(script, "@lattice-ui", "core").out)
|
|
4
4
|
local React = _core.React
|
|
5
5
|
local Slot = _core.Slot
|
|
6
|
+
local _motion = TS.import(script, TS.getModule(script, "@lattice-ui", "motion").out)
|
|
7
|
+
local createToggleResponseRecipe = _motion.createToggleResponseRecipe
|
|
8
|
+
local useResponseMotion = _motion.useResponseMotion
|
|
6
9
|
local useSwitchContext = TS.import(script, script.Parent, "context").useSwitchContext
|
|
10
|
+
local UNCHECKED_THUMB_POSITION = UDim2.fromOffset(2, 2)
|
|
11
|
+
local CHECKED_THUMB_POSITION = UDim2.new(1, -18, 0, 2)
|
|
7
12
|
local function SwitchThumb(props)
|
|
8
13
|
local switchContext = useSwitchContext()
|
|
14
|
+
local motionRef = useResponseMotion(switchContext.checked, {
|
|
15
|
+
active = {
|
|
16
|
+
Position = CHECKED_THUMB_POSITION,
|
|
17
|
+
},
|
|
18
|
+
inactive = {
|
|
19
|
+
Position = UNCHECKED_THUMB_POSITION,
|
|
20
|
+
},
|
|
21
|
+
}, createToggleResponseRecipe())
|
|
9
22
|
local child = props.children
|
|
10
23
|
if props.asChild then
|
|
11
24
|
if not React.isValidElement(child) then
|
|
12
25
|
error("[SwitchThumb] `asChild` requires a child element.")
|
|
13
26
|
end
|
|
14
|
-
return React.createElement(Slot,
|
|
27
|
+
return React.createElement(Slot, {
|
|
28
|
+
ref = motionRef,
|
|
29
|
+
}, child)
|
|
15
30
|
end
|
|
16
31
|
return React.createElement("frame", {
|
|
17
32
|
BackgroundColor3 = Color3.fromRGB(240, 244, 252),
|
|
18
33
|
BorderSizePixel = 0,
|
|
19
|
-
Position = if switchContext.checked then UDim2.new(1, -18, 0, 2) else UDim2.fromOffset(2, 2),
|
|
20
34
|
Size = UDim2.fromOffset(16, 16),
|
|
35
|
+
ref = motionRef,
|
|
21
36
|
}, child)
|
|
22
37
|
end
|
|
23
38
|
return {
|
package/package.json
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lattice-ui/switch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-next.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "out/init.luau",
|
|
6
6
|
"types": "out/index.d.ts",
|
|
7
|
+
"source": "src/index.ts",
|
|
7
8
|
"files": [
|
|
9
|
+
"default.project.json",
|
|
8
10
|
"out",
|
|
11
|
+
"src",
|
|
9
12
|
"README.md"
|
|
10
13
|
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/astra-void/lattice-ui.git"
|
|
17
|
+
},
|
|
11
18
|
"dependencies": {
|
|
12
|
-
"@lattice-ui/core": "0.
|
|
19
|
+
"@lattice-ui/core": "0.5.0-next.1",
|
|
20
|
+
"@lattice-ui/motion": "0.5.0-next.1"
|
|
13
21
|
},
|
|
14
22
|
"devDependencies": {
|
|
15
23
|
"@rbxts/react": "17.3.7-ts.1",
|
|
@@ -21,6 +29,8 @@
|
|
|
21
29
|
},
|
|
22
30
|
"scripts": {
|
|
23
31
|
"build": "rbxtsc -p tsconfig.json",
|
|
32
|
+
"lint": "eslint .",
|
|
33
|
+
"lint:fix": "eslint . --fix",
|
|
24
34
|
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
25
35
|
"watch": "rbxtsc -p tsconfig.json -w"
|
|
26
36
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { React, Slot, useControllableState } from "@lattice-ui/core";
|
|
2
|
+
import { createToggleResponseRecipe, useResponseMotion } from "@lattice-ui/motion";
|
|
3
|
+
import { SwitchContextProvider } from "./context";
|
|
4
|
+
import type { SwitchProps } from "./types";
|
|
5
|
+
|
|
6
|
+
const TRACK_ON_COLOR = Color3.fromRGB(86, 141, 255);
|
|
7
|
+
const TRACK_OFF_COLOR = Color3.fromRGB(66, 73, 91);
|
|
8
|
+
|
|
9
|
+
export function SwitchRoot(props: SwitchProps) {
|
|
10
|
+
const [checked, setCheckedState] = useControllableState<boolean>({
|
|
11
|
+
value: props.checked,
|
|
12
|
+
defaultValue: props.defaultChecked ?? false,
|
|
13
|
+
onChange: props.onCheckedChange,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const disabled = props.disabled === true;
|
|
17
|
+
|
|
18
|
+
const motionRef = useResponseMotion<GuiObject>(
|
|
19
|
+
checked,
|
|
20
|
+
{
|
|
21
|
+
active: { BackgroundColor3: TRACK_ON_COLOR },
|
|
22
|
+
inactive: { BackgroundColor3: TRACK_OFF_COLOR },
|
|
23
|
+
},
|
|
24
|
+
createToggleResponseRecipe(),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const setChecked = React.useCallback(
|
|
28
|
+
(nextChecked: boolean) => {
|
|
29
|
+
if (disabled) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
setCheckedState(nextChecked);
|
|
33
|
+
},
|
|
34
|
+
[disabled, setCheckedState],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const toggle = React.useCallback(() => {
|
|
38
|
+
if (disabled) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setCheckedState(!checked);
|
|
42
|
+
}, [checked, disabled, setCheckedState]);
|
|
43
|
+
|
|
44
|
+
const contextValue = React.useMemo(
|
|
45
|
+
() => ({
|
|
46
|
+
checked,
|
|
47
|
+
setChecked,
|
|
48
|
+
disabled,
|
|
49
|
+
}),
|
|
50
|
+
[checked, disabled, setChecked],
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const child = props.children;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<SwitchContextProvider value={contextValue}>
|
|
57
|
+
{props.asChild ? (
|
|
58
|
+
(() => {
|
|
59
|
+
if (!React.isValidElement(child)) {
|
|
60
|
+
error("[Switch] `asChild` requires a child element.");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Slot Active={!disabled} Event={{ Activated: toggle }} Selectable={!disabled} ref={motionRef}>
|
|
65
|
+
{child}
|
|
66
|
+
</Slot>
|
|
67
|
+
);
|
|
68
|
+
})()
|
|
69
|
+
) : (
|
|
70
|
+
<textbutton
|
|
71
|
+
Active={!disabled}
|
|
72
|
+
AutoButtonColor={false}
|
|
73
|
+
BorderSizePixel={0}
|
|
74
|
+
Event={{ Activated: toggle }}
|
|
75
|
+
Selectable={!disabled}
|
|
76
|
+
Size={UDim2.fromOffset(160, 36)}
|
|
77
|
+
Text={checked ? "On" : "Off"}
|
|
78
|
+
TextColor3={disabled ? Color3.fromRGB(145, 152, 168) : Color3.fromRGB(240, 244, 252)}
|
|
79
|
+
TextSize={15}
|
|
80
|
+
ref={motionRef as React.MutableRefObject<TextButton>}
|
|
81
|
+
>
|
|
82
|
+
{child}
|
|
83
|
+
</textbutton>
|
|
84
|
+
)}
|
|
85
|
+
</SwitchContextProvider>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { React, Slot } from "@lattice-ui/core";
|
|
2
|
+
import { createToggleResponseRecipe, useResponseMotion } from "@lattice-ui/motion";
|
|
3
|
+
import { useSwitchContext } from "./context";
|
|
4
|
+
import type { SwitchThumbProps } from "./types";
|
|
5
|
+
|
|
6
|
+
const UNCHECKED_THUMB_POSITION = UDim2.fromOffset(2, 2);
|
|
7
|
+
const CHECKED_THUMB_POSITION = new UDim2(1, -18, 0, 2);
|
|
8
|
+
|
|
9
|
+
export function SwitchThumb(props: SwitchThumbProps) {
|
|
10
|
+
const switchContext = useSwitchContext();
|
|
11
|
+
|
|
12
|
+
const motionRef = useResponseMotion<GuiObject>(
|
|
13
|
+
switchContext.checked,
|
|
14
|
+
{
|
|
15
|
+
active: { Position: CHECKED_THUMB_POSITION },
|
|
16
|
+
inactive: { Position: UNCHECKED_THUMB_POSITION },
|
|
17
|
+
},
|
|
18
|
+
createToggleResponseRecipe(),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const child = props.children;
|
|
22
|
+
|
|
23
|
+
if (props.asChild) {
|
|
24
|
+
if (!React.isValidElement(child)) {
|
|
25
|
+
error("[SwitchThumb] `asChild` requires a child element.");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return <Slot ref={motionRef}>{child}</Slot>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<frame
|
|
33
|
+
BackgroundColor3={Color3.fromRGB(240, 244, 252)}
|
|
34
|
+
BorderSizePixel={0}
|
|
35
|
+
Size={UDim2.fromOffset(16, 16)}
|
|
36
|
+
ref={motionRef as React.MutableRefObject<Frame>}
|
|
37
|
+
>
|
|
38
|
+
{child}
|
|
39
|
+
</frame>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type React from "@rbxts/react";
|
|
2
|
+
|
|
3
|
+
export type SwitchSetChecked = (checked: boolean) => void;
|
|
4
|
+
|
|
5
|
+
export type SwitchContextValue = {
|
|
6
|
+
checked: boolean;
|
|
7
|
+
setChecked: SwitchSetChecked;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type SwitchProps = {
|
|
12
|
+
checked?: boolean;
|
|
13
|
+
defaultChecked?: boolean;
|
|
14
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
asChild?: boolean;
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type SwitchThumbProps = {
|
|
21
|
+
forceMount?: boolean;
|
|
22
|
+
asChild?: boolean;
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SwitchRoot } from "./Switch/SwitchRoot";
|
|
2
|
+
import { SwitchThumb } from "./Switch/SwitchThumb";
|
|
3
|
+
|
|
4
|
+
export const Switch = {
|
|
5
|
+
Root: SwitchRoot,
|
|
6
|
+
Thumb: SwitchThumb,
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export type { SwitchContextValue, SwitchProps, SwitchThumbProps } from "./Switch/types";
|