@lattice-ui/select 0.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.
Files changed (40) hide show
  1. package/README.md +23 -0
  2. package/out/Select/SelectContent.d.ts +3 -0
  3. package/out/Select/SelectContent.luau +268 -0
  4. package/out/Select/SelectGroup.d.ts +3 -0
  5. package/out/Select/SelectGroup.luau +22 -0
  6. package/out/Select/SelectItem.d.ts +3 -0
  7. package/out/Select/SelectItem.luau +124 -0
  8. package/out/Select/SelectLabel.d.ts +3 -0
  9. package/out/Select/SelectLabel.luau +26 -0
  10. package/out/Select/SelectPortal.d.ts +3 -0
  11. package/out/Select/SelectPortal.luau +33 -0
  12. package/out/Select/SelectRoot.d.ts +3 -0
  13. package/out/Select/SelectRoot.luau +201 -0
  14. package/out/Select/SelectSeparator.d.ts +3 -0
  15. package/out/Select/SelectSeparator.luau +22 -0
  16. package/out/Select/SelectTrigger.d.ts +3 -0
  17. package/out/Select/SelectTrigger.luau +72 -0
  18. package/out/Select/SelectValue.d.ts +3 -0
  19. package/out/Select/SelectValue.luau +47 -0
  20. package/out/Select/context.d.ts +3 -0
  21. package/out/Select/context.luau +10 -0
  22. package/out/Select/types.d.ts +84 -0
  23. package/out/Select/types.luau +2 -0
  24. package/out/index.d.ts +22 -0
  25. package/out/init.luau +34 -0
  26. package/package.json +26 -0
  27. package/src/Select/SelectContent.tsx +297 -0
  28. package/src/Select/SelectGroup.tsx +19 -0
  29. package/src/Select/SelectItem.tsx +132 -0
  30. package/src/Select/SelectLabel.tsx +27 -0
  31. package/src/Select/SelectPortal.tsx +28 -0
  32. package/src/Select/SelectRoot.tsx +124 -0
  33. package/src/Select/SelectSeparator.tsx +19 -0
  34. package/src/Select/SelectTrigger.tsx +89 -0
  35. package/src/Select/SelectValue.tsx +42 -0
  36. package/src/Select/context.ts +6 -0
  37. package/src/Select/types.ts +96 -0
  38. package/src/index.ts +59 -0
  39. package/tsconfig.json +16 -0
  40. package/tsconfig.typecheck.json +35 -0
@@ -0,0 +1,89 @@
1
+ import { React, Slot } from "@lattice-ui/core";
2
+ import { useSelectContext } from "./context";
3
+ import type { SelectTriggerProps } from "./types";
4
+
5
+ function toGuiObject(instance: Instance | undefined) {
6
+ if (!instance || !instance.IsA("GuiObject")) {
7
+ return undefined;
8
+ }
9
+
10
+ return instance;
11
+ }
12
+
13
+ export function SelectTrigger(props: SelectTriggerProps) {
14
+ const selectContext = useSelectContext();
15
+ const disabled = selectContext.disabled || props.disabled === true;
16
+
17
+ const setTriggerRef = React.useCallback(
18
+ (instance: Instance | undefined) => {
19
+ selectContext.triggerRef.current = toGuiObject(instance);
20
+ },
21
+ [selectContext.triggerRef],
22
+ );
23
+
24
+ const handleActivated = React.useCallback(() => {
25
+ if (disabled) {
26
+ return;
27
+ }
28
+
29
+ selectContext.setOpen(!selectContext.open);
30
+ }, [disabled, selectContext]);
31
+
32
+ const handleInputBegan = React.useCallback(
33
+ (_rbx: GuiObject, inputObject: InputObject) => {
34
+ if (disabled) {
35
+ return;
36
+ }
37
+
38
+ const keyCode = inputObject.KeyCode;
39
+ if (keyCode === Enum.KeyCode.Return || keyCode === Enum.KeyCode.Space) {
40
+ selectContext.setOpen(!selectContext.open);
41
+ return;
42
+ }
43
+
44
+ if (keyCode === Enum.KeyCode.Down || keyCode === Enum.KeyCode.Up) {
45
+ selectContext.setOpen(true);
46
+ }
47
+ },
48
+ [disabled, selectContext],
49
+ );
50
+
51
+ const eventHandlers = React.useMemo(
52
+ () => ({
53
+ Activated: handleActivated,
54
+ InputBegan: handleInputBegan,
55
+ }),
56
+ [handleActivated, handleInputBegan],
57
+ );
58
+
59
+ if (props.asChild) {
60
+ const child = props.children;
61
+ if (!child) {
62
+ error("[SelectTrigger] `asChild` requires a child element.");
63
+ }
64
+
65
+ return (
66
+ <Slot Active={!disabled} Event={eventHandlers} Selectable={!disabled} ref={setTriggerRef}>
67
+ {child}
68
+ </Slot>
69
+ );
70
+ }
71
+
72
+ return (
73
+ <textbutton
74
+ Active={!disabled}
75
+ AutoButtonColor={false}
76
+ BackgroundColor3={Color3.fromRGB(41, 48, 63)}
77
+ BorderSizePixel={0}
78
+ Event={eventHandlers}
79
+ Selectable={!disabled}
80
+ Size={UDim2.fromOffset(220, 36)}
81
+ Text="Select"
82
+ TextColor3={disabled ? Color3.fromRGB(140, 148, 164) : Color3.fromRGB(235, 241, 248)}
83
+ TextSize={15}
84
+ ref={setTriggerRef}
85
+ >
86
+ {props.children}
87
+ </textbutton>
88
+ );
89
+ }
@@ -0,0 +1,42 @@
1
+ import { React, Slot } from "@lattice-ui/core";
2
+ import { useSelectContext } from "./context";
3
+ import type { SelectValueProps } from "./types";
4
+
5
+ export function SelectValue(props: SelectValueProps) {
6
+ const selectContext = useSelectContext();
7
+ const selectedValue = selectContext.value;
8
+ const hasValue = selectedValue !== undefined;
9
+
10
+ const resolvedText = React.useMemo(() => {
11
+ if (!hasValue || selectedValue === undefined) {
12
+ return props.placeholder ?? "";
13
+ }
14
+
15
+ return selectContext.getItemText(selectedValue) ?? selectedValue;
16
+ }, [hasValue, props.placeholder, selectContext, selectedValue]);
17
+
18
+ if (props.asChild) {
19
+ const child = props.children;
20
+ if (!child) {
21
+ error("[SelectValue] `asChild` requires a child element.");
22
+ }
23
+
24
+ return (
25
+ <Slot Name="SelectValue" Text={resolvedText}>
26
+ {child}
27
+ </Slot>
28
+ );
29
+ }
30
+
31
+ return (
32
+ <textlabel
33
+ BackgroundTransparency={1}
34
+ BorderSizePixel={0}
35
+ Size={UDim2.fromOffset(200, 20)}
36
+ Text={resolvedText}
37
+ TextColor3={hasValue ? Color3.fromRGB(235, 240, 248) : Color3.fromRGB(153, 161, 177)}
38
+ TextSize={14}
39
+ TextXAlignment={Enum.TextXAlignment.Left}
40
+ />
41
+ );
42
+ }
@@ -0,0 +1,6 @@
1
+ import { createStrictContext } from "@lattice-ui/core";
2
+ import type { SelectContextValue } from "./types";
3
+
4
+ const [SelectContextProvider, useSelectContext] = createStrictContext<SelectContextValue>("Select");
5
+
6
+ export { SelectContextProvider, useSelectContext };
@@ -0,0 +1,96 @@
1
+ import type { LayerInteractEvent } from "@lattice-ui/layer";
2
+ import type { PopperPlacement } from "@lattice-ui/popper";
3
+ import type React from "@rbxts/react";
4
+
5
+ export type SelectSetOpen = (open: boolean) => void;
6
+ export type SelectSetValue = (value: string) => void;
7
+
8
+ export type SelectItemRegistration = {
9
+ id: number;
10
+ value: string;
11
+ order: number;
12
+ getNode: () => GuiObject | undefined;
13
+ getDisabled: () => boolean;
14
+ getTextValue: () => string;
15
+ };
16
+
17
+ export type SelectContextValue = {
18
+ open: boolean;
19
+ setOpen: SelectSetOpen;
20
+ value?: string;
21
+ setValue: SelectSetValue;
22
+ disabled: boolean;
23
+ required: boolean;
24
+ loop: boolean;
25
+ triggerRef: React.MutableRefObject<GuiObject | undefined>;
26
+ contentRef: React.MutableRefObject<GuiObject | undefined>;
27
+ registerItem: (item: SelectItemRegistration) => () => void;
28
+ getOrderedItems: () => Array<SelectItemRegistration>;
29
+ getItemText: (value: string) => string | undefined;
30
+ };
31
+
32
+ export type SelectProps = {
33
+ value?: string;
34
+ defaultValue?: string;
35
+ onValueChange?: (value: string) => void;
36
+ open?: boolean;
37
+ defaultOpen?: boolean;
38
+ onOpenChange?: (open: boolean) => void;
39
+ disabled?: boolean;
40
+ required?: boolean;
41
+ loop?: boolean;
42
+ children?: React.ReactNode;
43
+ };
44
+
45
+ export type SelectTriggerProps = {
46
+ asChild?: boolean;
47
+ disabled?: boolean;
48
+ children?: React.ReactElement;
49
+ };
50
+
51
+ export type SelectValueProps = {
52
+ asChild?: boolean;
53
+ placeholder?: string;
54
+ children?: React.ReactElement;
55
+ };
56
+
57
+ export type SelectPortalProps = {
58
+ container?: BasePlayerGui;
59
+ displayOrderBase?: number;
60
+ children?: React.ReactNode;
61
+ };
62
+
63
+ export type SelectContentProps = {
64
+ asChild?: boolean;
65
+ forceMount?: boolean;
66
+ placement?: PopperPlacement;
67
+ offset?: Vector2;
68
+ padding?: number;
69
+ onEscapeKeyDown?: (event: LayerInteractEvent) => void;
70
+ onPointerDownOutside?: (event: LayerInteractEvent) => void;
71
+ onInteractOutside?: (event: LayerInteractEvent) => void;
72
+ children?: React.ReactNode;
73
+ };
74
+
75
+ export type SelectItemProps = {
76
+ value: string;
77
+ textValue?: string;
78
+ disabled?: boolean;
79
+ asChild?: boolean;
80
+ children?: React.ReactElement;
81
+ };
82
+
83
+ export type SelectSeparatorProps = {
84
+ asChild?: boolean;
85
+ children?: React.ReactElement;
86
+ };
87
+
88
+ export type SelectGroupProps = {
89
+ asChild?: boolean;
90
+ children?: React.ReactElement;
91
+ };
92
+
93
+ export type SelectLabelProps = {
94
+ asChild?: boolean;
95
+ children?: React.ReactElement;
96
+ };
package/src/index.ts ADDED
@@ -0,0 +1,59 @@
1
+ import { SelectContent } from "./Select/SelectContent";
2
+ import { SelectGroup } from "./Select/SelectGroup";
3
+ import { SelectItem } from "./Select/SelectItem";
4
+ import { SelectLabel } from "./Select/SelectLabel";
5
+ import { SelectPortal } from "./Select/SelectPortal";
6
+ import { SelectRoot } from "./Select/SelectRoot";
7
+ import { SelectSeparator } from "./Select/SelectSeparator";
8
+ import { SelectTrigger } from "./Select/SelectTrigger";
9
+ import { SelectValue } from "./Select/SelectValue";
10
+
11
+ export const Select = {
12
+ Root: SelectRoot,
13
+ Trigger: SelectTrigger,
14
+ Value: SelectValue,
15
+ Portal: SelectPortal,
16
+ Content: SelectContent,
17
+ Item: SelectItem,
18
+ Group: SelectGroup,
19
+ Label: SelectLabel,
20
+ Separator: SelectSeparator,
21
+ } as const satisfies {
22
+ Root: typeof SelectRoot;
23
+ Trigger: typeof SelectTrigger;
24
+ Value: typeof SelectValue;
25
+ Portal: typeof SelectPortal;
26
+ Content: typeof SelectContent;
27
+ Item: typeof SelectItem;
28
+ Group: typeof SelectGroup;
29
+ Label: typeof SelectLabel;
30
+ Separator: typeof SelectSeparator;
31
+ };
32
+
33
+ export {
34
+ SelectContent,
35
+ SelectGroup,
36
+ SelectItem,
37
+ SelectLabel,
38
+ SelectPortal,
39
+ SelectRoot,
40
+ SelectSeparator,
41
+ SelectTrigger,
42
+ SelectValue,
43
+ };
44
+
45
+ export type {
46
+ SelectContentProps,
47
+ SelectContextValue,
48
+ SelectGroupProps,
49
+ SelectItemProps,
50
+ SelectItemRegistration,
51
+ SelectLabelProps,
52
+ SelectPortalProps,
53
+ SelectProps,
54
+ SelectSeparatorProps,
55
+ SelectSetOpen,
56
+ SelectSetValue,
57
+ SelectTriggerProps,
58
+ SelectValueProps,
59
+ } from "./Select/types";
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "out",
6
+ "declaration": true,
7
+ "typeRoots": [
8
+ "./node_modules/@rbxts",
9
+ "../../node_modules/@rbxts",
10
+ "./node_modules/@lattice-ui",
11
+ "../../node_modules/@lattice-ui"
12
+ ],
13
+ "types": ["types", "compiler-types"]
14
+ },
15
+ "include": ["src"]
16
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "baseUrl": "..",
6
+ "rootDir": "..",
7
+ "paths": {
8
+ "@lattice-ui/accordion": ["accordion/src/index.ts"],
9
+ "@lattice-ui/avatar": ["avatar/src/index.ts"],
10
+ "@lattice-ui/checkbox": ["checkbox/src/index.ts"],
11
+ "@lattice-ui/combobox": ["combobox/src/index.ts"],
12
+ "@lattice-ui/core": ["core/src/index.ts"],
13
+ "@lattice-ui/dialog": ["dialog/src/index.ts"],
14
+ "@lattice-ui/focus": ["focus/src/index.ts"],
15
+ "@lattice-ui/layer": ["layer/src/index.ts"],
16
+ "@lattice-ui/menu": ["menu/src/index.ts"],
17
+ "@lattice-ui/popover": ["popover/src/index.ts"],
18
+ "@lattice-ui/popper": ["popper/src/index.ts"],
19
+ "@lattice-ui/progress": ["progress/src/index.ts"],
20
+ "@lattice-ui/radio-group": ["radio-group/src/index.ts"],
21
+ "@lattice-ui/scroll-area": ["scroll-area/src/index.ts"],
22
+ "@lattice-ui/select": ["select/src/index.ts"],
23
+ "@lattice-ui/slider": ["slider/src/index.ts"],
24
+ "@lattice-ui/style": ["style/src/index.ts"],
25
+ "@lattice-ui/switch": ["switch/src/index.ts"],
26
+ "@lattice-ui/system": ["system/src/index.ts"],
27
+ "@lattice-ui/tabs": ["tabs/src/index.ts"],
28
+ "@lattice-ui/text-field": ["text-field/src/index.ts"],
29
+ "@lattice-ui/textarea": ["textarea/src/index.ts"],
30
+ "@lattice-ui/toast": ["toast/src/index.ts"],
31
+ "@lattice-ui/toggle-group": ["toggle-group/src/index.ts"],
32
+ "@lattice-ui/tooltip": ["tooltip/src/index.ts"]
33
+ }
34
+ }
35
+ }