@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.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "switch",
3
+ "tree": {
4
+ "$path": "out",
5
+ "out": {
6
+ "$path": "out"
7
+ }
8
+ }
9
+ }
@@ -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, nil, child)
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.4.3",
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.4.3"
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,6 @@
1
+ import { createStrictContext } from "@lattice-ui/core";
2
+ import type { SwitchContextValue } from "./types";
3
+
4
+ const [SwitchContextProvider, useSwitchContext] = createStrictContext<SwitchContextValue>("Switch");
5
+
6
+ export { SwitchContextProvider, useSwitchContext };
@@ -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";