@rovula/ui 0.0.77 → 0.0.79
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/dist/cjs/bundle.css +43 -3
- package/dist/cjs/bundle.js +3 -3
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +3 -0
- package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +5 -1
- package/dist/cjs/types/components/MaskedTextInput/MaskedTextInput.d.ts +75 -0
- package/dist/cjs/types/components/MaskedTextInput/MaskedTextInput.stories.d.ts +491 -0
- package/dist/cjs/types/components/MaskedTextInput/index.d.ts +3 -0
- package/dist/cjs/types/components/Menu/Menu.d.ts +65 -0
- package/dist/cjs/types/components/Menu/Menu.stories.d.ts +31 -0
- package/dist/cjs/types/components/Menu/helpers.d.ts +19 -0
- package/dist/cjs/types/components/Menu/index.d.ts +4 -0
- package/dist/cjs/types/components/Search/Search.d.ts +46 -3
- package/dist/cjs/types/components/Search/Search.stories.d.ts +46 -27
- package/dist/cjs/types/index.d.ts +3 -0
- package/dist/components/Dropdown/Dropdown.js +41 -19
- package/dist/components/Dropdown/Dropdown.stories.js +13 -0
- package/dist/components/MaskedTextInput/MaskedTextInput.js +267 -0
- package/dist/components/MaskedTextInput/MaskedTextInput.stories.js +167 -0
- package/dist/components/MaskedTextInput/index.js +2 -0
- package/dist/components/Menu/Menu.js +64 -0
- package/dist/components/Menu/Menu.stories.js +406 -0
- package/dist/components/Menu/helpers.js +28 -0
- package/dist/components/Menu/index.js +3 -0
- package/dist/components/Toast/Toast.styles.js +1 -1
- package/dist/esm/bundle.css +43 -3
- package/dist/esm/bundle.js +3 -3
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/Dropdown/Dropdown.d.ts +3 -0
- package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +5 -1
- package/dist/esm/types/components/MaskedTextInput/MaskedTextInput.d.ts +75 -0
- package/dist/esm/types/components/MaskedTextInput/MaskedTextInput.stories.d.ts +491 -0
- package/dist/esm/types/components/MaskedTextInput/index.d.ts +3 -0
- package/dist/esm/types/components/Menu/Menu.d.ts +65 -0
- package/dist/esm/types/components/Menu/Menu.stories.d.ts +31 -0
- package/dist/esm/types/components/Menu/helpers.d.ts +19 -0
- package/dist/esm/types/components/Menu/index.d.ts +4 -0
- package/dist/esm/types/components/Search/Search.d.ts +46 -3
- package/dist/esm/types/components/Search/Search.stories.d.ts +46 -27
- package/dist/esm/types/index.d.ts +3 -0
- package/dist/index.d.ts +169 -3
- package/dist/index.js +2 -0
- package/dist/src/theme/global.css +55 -4
- package/package.json +1 -1
- package/src/components/Dropdown/Dropdown.stories.tsx +31 -0
- package/src/components/Dropdown/Dropdown.tsx +73 -54
- package/src/components/MaskedTextInput/MaskedTextInput.stories.tsx +414 -0
- package/src/components/MaskedTextInput/MaskedTextInput.tsx +391 -0
- package/src/components/MaskedTextInput/README.md +202 -0
- package/src/components/MaskedTextInput/index.ts +3 -0
- package/src/components/Menu/Menu.stories.tsx +586 -0
- package/src/components/Menu/Menu.tsx +235 -0
- package/src/components/Menu/helpers.ts +45 -0
- package/src/components/Menu/index.ts +7 -0
- package/src/components/Search/Search.tsx +24 -11
- package/src/components/Toast/Toast.styles.tsx +1 -1
- package/src/index.ts +6 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React, { CSSProperties, ReactNode } from "react";
|
|
2
|
+
export type MenuOption = {
|
|
3
|
+
value: string;
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
/**
|
|
6
|
+
* Visual type - กำหนดว่าจะแสดง icon อะไร
|
|
7
|
+
* - "default": ไม่มี icon (แค่ highlight background)
|
|
8
|
+
* - "checkbox": แสดง ✓ icon
|
|
9
|
+
* - "radio": แสดง ● icon
|
|
10
|
+
*/
|
|
11
|
+
type?: "default" | "checkbox" | "radio";
|
|
12
|
+
icon?: ReactNode;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
danger?: boolean;
|
|
15
|
+
checked?: boolean;
|
|
16
|
+
onClick?: () => void;
|
|
17
|
+
};
|
|
18
|
+
export type MenuItemType = {
|
|
19
|
+
type: "item";
|
|
20
|
+
item: MenuOption;
|
|
21
|
+
} | {
|
|
22
|
+
type: "separator";
|
|
23
|
+
} | {
|
|
24
|
+
type: "label";
|
|
25
|
+
label: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: "custom";
|
|
28
|
+
render: () => ReactNode;
|
|
29
|
+
};
|
|
30
|
+
export type MenuProps = {
|
|
31
|
+
items: MenuItemType[];
|
|
32
|
+
/**
|
|
33
|
+
* Selected values - ใช้กับ type="item"
|
|
34
|
+
*/
|
|
35
|
+
selectedValues?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Callback เมื่อเลือก item
|
|
38
|
+
* - ถ้า item.type="checkbox" → toggle checked state
|
|
39
|
+
* - ถ้า item.type="radio" → single select (clear others)
|
|
40
|
+
* - ถ้า item.type="default" หรือไม่ระบุ → ตาม selectedValues
|
|
41
|
+
*/
|
|
42
|
+
onSelect?: (value: string, item: MenuOption) => void;
|
|
43
|
+
className?: string;
|
|
44
|
+
style?: CSSProperties;
|
|
45
|
+
isAbove?: boolean;
|
|
46
|
+
};
|
|
47
|
+
export declare const Menu: React.ForwardRefExoticComponent<MenuProps & React.RefAttributes<HTMLDivElement>>;
|
|
48
|
+
type MenuItemProps = {
|
|
49
|
+
option: MenuOption;
|
|
50
|
+
visualType: "default" | "checkbox" | "radio";
|
|
51
|
+
isChecked: boolean;
|
|
52
|
+
onSelect: () => void;
|
|
53
|
+
className?: string;
|
|
54
|
+
};
|
|
55
|
+
export declare const MenuItem: React.ForwardRefExoticComponent<MenuItemProps & React.RefAttributes<HTMLDivElement>>;
|
|
56
|
+
type MenuSeparatorProps = {
|
|
57
|
+
className?: string;
|
|
58
|
+
};
|
|
59
|
+
export declare const MenuSeparator: React.ForwardRefExoticComponent<MenuSeparatorProps & React.RefAttributes<HTMLDivElement>>;
|
|
60
|
+
type MenuLabelProps = {
|
|
61
|
+
children: ReactNode;
|
|
62
|
+
className?: string;
|
|
63
|
+
};
|
|
64
|
+
export declare const MenuLabel: React.ForwardRefExoticComponent<MenuLabelProps & React.RefAttributes<HTMLDivElement>>;
|
|
65
|
+
export default Menu;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { StoryObj } from "@storybook/react";
|
|
3
|
+
import { Menu, MenuItemType } from "./Menu";
|
|
4
|
+
declare const meta: {
|
|
5
|
+
title: string;
|
|
6
|
+
component: React.ForwardRefExoticComponent<import("./Menu").MenuProps & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
tags: string[];
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: string;
|
|
10
|
+
};
|
|
11
|
+
decorators: ((Story: import("@storybook/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
|
|
12
|
+
items: MenuItemType[];
|
|
13
|
+
selectedValues?: string[] | undefined;
|
|
14
|
+
onSelect?: ((value: string, item: import("./Menu").MenuOption) => void) | undefined;
|
|
15
|
+
className?: string | undefined;
|
|
16
|
+
style?: React.CSSProperties | undefined;
|
|
17
|
+
isAbove?: boolean | undefined;
|
|
18
|
+
ref?: React.LegacyRef<HTMLDivElement> | undefined;
|
|
19
|
+
key?: React.Key | null | undefined;
|
|
20
|
+
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
21
|
+
};
|
|
22
|
+
export default meta;
|
|
23
|
+
export declare const Basic: StoryObj<typeof Menu>;
|
|
24
|
+
export declare const WithIcons: StoryObj<typeof Menu>;
|
|
25
|
+
export declare const WithCheckbox: StoryObj<typeof Menu>;
|
|
26
|
+
export declare const WithRadio: StoryObj<typeof Menu>;
|
|
27
|
+
export declare const ComplexMenu: StoryObj<typeof Menu>;
|
|
28
|
+
export declare const WithDropdownTrigger: StoryObj<typeof Menu>;
|
|
29
|
+
export declare const CustomItems: StoryObj<typeof Menu>;
|
|
30
|
+
export declare const DropdownPattern: StoryObj<typeof Menu>;
|
|
31
|
+
export declare const MultiSelectPattern: StoryObj<typeof Menu>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MenuItemType } from "./Menu";
|
|
2
|
+
/**
|
|
3
|
+
* Helper function to convert simple options to MenuItemType
|
|
4
|
+
* Useful for integrating with Dropdown component
|
|
5
|
+
*/
|
|
6
|
+
export declare function optionsToMenuItems(options: Array<{
|
|
7
|
+
value: string;
|
|
8
|
+
label: string | React.ReactNode;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
renderLabel?: any;
|
|
11
|
+
}>): MenuItemType[];
|
|
12
|
+
/**
|
|
13
|
+
* Helper to add separator between menu items
|
|
14
|
+
*/
|
|
15
|
+
export declare function withSeparator(items: MenuItemType[], atIndex: number): MenuItemType[];
|
|
16
|
+
/**
|
|
17
|
+
* Helper to add label/header to menu items
|
|
18
|
+
*/
|
|
19
|
+
export declare function withLabel(label: string, items: MenuItemType[]): MenuItemType[];
|
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { Options } from "../Dropdown/Dropdown";
|
|
3
|
+
import { InputProps } from "../TextInput/TextInput";
|
|
4
|
+
export type SearchProps = {
|
|
5
|
+
id?: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
size?: "sm" | "md" | "lg";
|
|
8
|
+
rounded?: "none" | "normal" | "full";
|
|
9
|
+
variant?: "flat" | "outline" | "underline";
|
|
10
|
+
helperText?: string;
|
|
11
|
+
errorMessage?: string;
|
|
12
|
+
fullwidth?: boolean;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
error?: boolean;
|
|
15
|
+
required?: boolean;
|
|
16
|
+
modal?: boolean;
|
|
17
|
+
className?: string;
|
|
18
|
+
optionContainerClassName?: string;
|
|
19
|
+
optionItemClassName?: string;
|
|
20
|
+
optionNotFoundItemClassName?: string;
|
|
21
|
+
options: Options[];
|
|
22
|
+
value?: Options;
|
|
23
|
+
onChangeText?: InputProps["onChange"];
|
|
24
|
+
onSelect?: (value: Options) => void;
|
|
25
|
+
} & Omit<InputProps, "value" | "onSelect">;
|
|
26
|
+
declare const Search: React.ForwardRefExoticComponent<{
|
|
27
|
+
id?: string;
|
|
28
|
+
label?: string;
|
|
29
|
+
size?: "sm" | "md" | "lg";
|
|
30
|
+
rounded?: "none" | "normal" | "full";
|
|
31
|
+
variant?: "flat" | "outline" | "underline";
|
|
32
|
+
helperText?: string;
|
|
33
|
+
errorMessage?: string;
|
|
34
|
+
fullwidth?: boolean;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
error?: boolean;
|
|
37
|
+
required?: boolean;
|
|
38
|
+
modal?: boolean;
|
|
39
|
+
className?: string;
|
|
40
|
+
optionContainerClassName?: string;
|
|
41
|
+
optionItemClassName?: string;
|
|
42
|
+
optionNotFoundItemClassName?: string;
|
|
43
|
+
options: Options[];
|
|
44
|
+
value?: Options;
|
|
45
|
+
onChangeText?: InputProps["onChange"];
|
|
46
|
+
onSelect?: (value: Options) => void;
|
|
47
|
+
} & Omit<InputProps, "onSelect" | "value"> & React.RefAttributes<HTMLInputElement>>;
|
|
5
48
|
export { Search };
|
|
@@ -2,18 +2,56 @@ import React from "react";
|
|
|
2
2
|
import { Options } from "../Dropdown/Dropdown";
|
|
3
3
|
declare const meta: {
|
|
4
4
|
title: string;
|
|
5
|
-
component: React.ForwardRefExoticComponent<
|
|
5
|
+
component: React.ForwardRefExoticComponent<{
|
|
6
|
+
id?: string;
|
|
7
|
+
label?: string;
|
|
8
|
+
size?: "sm" | "md" | "lg";
|
|
9
|
+
rounded?: "none" | "normal" | "full";
|
|
10
|
+
variant?: "flat" | "outline" | "underline";
|
|
11
|
+
helperText?: string;
|
|
12
|
+
errorMessage?: string;
|
|
13
|
+
fullwidth?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
error?: boolean;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
modal?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
optionContainerClassName?: string;
|
|
20
|
+
optionItemClassName?: string;
|
|
21
|
+
optionNotFoundItemClassName?: string;
|
|
22
|
+
options: Options[];
|
|
23
|
+
value?: Options;
|
|
24
|
+
onChangeText?: import("../..").InputProps["onChange"];
|
|
25
|
+
onSelect?: (value: Options) => void;
|
|
26
|
+
} & Omit<import("../..").InputProps, "onSelect" | "value"> & React.RefAttributes<HTMLInputElement>>;
|
|
6
27
|
tags: string[];
|
|
7
28
|
parameters: {
|
|
8
29
|
layout: string;
|
|
9
30
|
};
|
|
10
31
|
decorators: ((Story: import("@storybook/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
|
|
32
|
+
id?: string | undefined;
|
|
33
|
+
label?: string | undefined;
|
|
34
|
+
size?: "sm" | "md" | "lg" | undefined;
|
|
35
|
+
rounded?: "none" | "normal" | "full" | undefined;
|
|
11
36
|
variant?: "flat" | "outline" | "underline" | undefined;
|
|
12
|
-
|
|
37
|
+
helperText?: string | undefined;
|
|
38
|
+
errorMessage?: string | undefined;
|
|
39
|
+
fullwidth?: boolean | undefined;
|
|
40
|
+
disabled?: boolean | undefined;
|
|
41
|
+
error?: boolean | undefined;
|
|
42
|
+
required?: boolean | undefined;
|
|
43
|
+
modal?: boolean | undefined;
|
|
13
44
|
className?: string | undefined;
|
|
45
|
+
optionContainerClassName?: string | undefined;
|
|
46
|
+
optionItemClassName?: string | undefined;
|
|
47
|
+
optionNotFoundItemClassName?: string | undefined;
|
|
48
|
+
options: Options[];
|
|
49
|
+
value?: Options | undefined;
|
|
50
|
+
onChangeText?: React.ChangeEventHandler<HTMLInputElement> | undefined;
|
|
51
|
+
onSelect?: ((value: Options) => void) | undefined;
|
|
52
|
+
suppressHydrationWarning?: boolean | undefined | undefined;
|
|
14
53
|
color?: string | undefined | undefined;
|
|
15
54
|
height?: number | string | undefined | undefined;
|
|
16
|
-
id?: string | undefined;
|
|
17
55
|
lang?: string | undefined | undefined;
|
|
18
56
|
max?: number | string | undefined | undefined;
|
|
19
57
|
min?: number | string | undefined | undefined;
|
|
@@ -200,7 +238,6 @@ declare const meta: {
|
|
|
200
238
|
onMouseOverCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
|
|
201
239
|
onMouseUp?: React.MouseEventHandler<HTMLInputElement> | undefined;
|
|
202
240
|
onMouseUpCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
|
|
203
|
-
onSelect?: ((value: Options) => void) | undefined;
|
|
204
241
|
onSelectCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
|
|
205
242
|
onTouchCancel?: React.TouchEventHandler<HTMLInputElement> | undefined;
|
|
206
243
|
onTouchCancelCapture?: React.TouchEventHandler<HTMLInputElement> | undefined;
|
|
@@ -243,18 +280,14 @@ declare const meta: {
|
|
|
243
280
|
form?: string | undefined | undefined;
|
|
244
281
|
list?: string | undefined | undefined;
|
|
245
282
|
step?: number | string | undefined | undefined;
|
|
246
|
-
error?: boolean | undefined;
|
|
247
|
-
size?: "sm" | "md" | "lg" | undefined;
|
|
248
|
-
disabled?: boolean | undefined;
|
|
249
|
-
fullwidth?: boolean | undefined;
|
|
250
283
|
title?: string | undefined | undefined;
|
|
251
284
|
startIcon?: React.ReactNode;
|
|
285
|
+
endIcon?: React.ReactNode;
|
|
252
286
|
formAction?: string | undefined;
|
|
253
287
|
formEncType?: string | undefined | undefined;
|
|
254
288
|
formMethod?: string | undefined | undefined;
|
|
255
289
|
formNoValidate?: boolean | undefined | undefined;
|
|
256
290
|
formTarget?: string | undefined | undefined;
|
|
257
|
-
value?: Options | undefined;
|
|
258
291
|
defaultChecked?: boolean | undefined | undefined;
|
|
259
292
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
260
293
|
suppressContentEditableWarning?: boolean | undefined | undefined;
|
|
@@ -295,7 +328,9 @@ declare const meta: {
|
|
|
295
328
|
unselectable?: "on" | "off" | undefined | undefined;
|
|
296
329
|
inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
|
|
297
330
|
is?: string | undefined | undefined;
|
|
298
|
-
|
|
331
|
+
hasClearIcon?: boolean | undefined;
|
|
332
|
+
hasSearchIcon?: boolean | undefined;
|
|
333
|
+
isFloatingLabel?: boolean | undefined;
|
|
299
334
|
accept?: string | undefined | undefined;
|
|
300
335
|
alt?: string | undefined | undefined;
|
|
301
336
|
autoComplete?: React.HTMLInputAutoCompleteAttribute | undefined;
|
|
@@ -307,12 +342,9 @@ declare const meta: {
|
|
|
307
342
|
pattern?: string | undefined | undefined;
|
|
308
343
|
placeholder?: string | undefined | undefined;
|
|
309
344
|
readOnly?: boolean | undefined | undefined;
|
|
310
|
-
required?: boolean | undefined;
|
|
311
345
|
src?: string | undefined | undefined;
|
|
312
|
-
label?: string | undefined;
|
|
313
346
|
iconMode?: "flat" | "solid" | undefined;
|
|
314
|
-
|
|
315
|
-
errorMessage?: string | undefined;
|
|
347
|
+
keepCloseIconOnValue?: boolean | undefined;
|
|
316
348
|
labelClassName?: string | undefined;
|
|
317
349
|
classes?: {
|
|
318
350
|
iconWrapper?: string;
|
|
@@ -325,19 +357,6 @@ declare const meta: {
|
|
|
325
357
|
onClickEndIcon?: (() => void) | undefined;
|
|
326
358
|
renderStartIcon?: (() => React.ReactNode) | undefined;
|
|
327
359
|
renderEndIcon?: (() => React.ReactNode) | undefined;
|
|
328
|
-
modal?: boolean | undefined;
|
|
329
|
-
optionContainerClassName?: string | undefined;
|
|
330
|
-
optionItemClassName?: string | undefined;
|
|
331
|
-
optionNotFoundItemClassName?: string | undefined;
|
|
332
|
-
options: Options[];
|
|
333
|
-
onChangeText?: React.ChangeEventHandler<HTMLInputElement> | undefined;
|
|
334
|
-
renderOptions?: ((value: {
|
|
335
|
-
optionsFiltered: Options[];
|
|
336
|
-
selectedOption: Options | null | undefined;
|
|
337
|
-
onClick: (option: Options) => void;
|
|
338
|
-
style?: React.CSSProperties;
|
|
339
|
-
dropdownRef?: React.RefObject<HTMLUListElement>;
|
|
340
|
-
}) => React.ReactNode) | undefined;
|
|
341
360
|
ref?: React.LegacyRef<HTMLInputElement> | undefined;
|
|
342
361
|
key?: React.Key | null | undefined;
|
|
343
362
|
}>) => import("react/jsx-runtime").JSX.Element)[];
|
|
@@ -2,6 +2,7 @@ import "./theme/global.css";
|
|
|
2
2
|
import "./icons/iconConfig";
|
|
3
3
|
export { default as Button } from "./components/Button/Button";
|
|
4
4
|
export { default as TextInput } from "./components/TextInput/TextInput";
|
|
5
|
+
export { default as MaskedTextInput } from "./components/MaskedTextInput";
|
|
5
6
|
export { NumberInput } from "./components/NumberInput/NumberInput";
|
|
6
7
|
export { default as TextArea } from "./components/TextArea/TextArea";
|
|
7
8
|
export { default as Text } from "./components/Text/Text";
|
|
@@ -29,6 +30,7 @@ export * from "./components/InputFilter/InputFilter";
|
|
|
29
30
|
export * from "./components/Slider/Slider";
|
|
30
31
|
export * from "./components/Switch/Switch";
|
|
31
32
|
export * from "./components/DropdownMenu/DropdownMenu";
|
|
33
|
+
export * from "./components/Menu/Menu";
|
|
32
34
|
export * from "./components/Tooltip/Tooltip";
|
|
33
35
|
export * from "./components/Tooltip/TooltipSimple";
|
|
34
36
|
export * from "./components/Toast/Toast";
|
|
@@ -39,6 +41,7 @@ export * from "./components/FocusedScrollView/FocusedScrollView";
|
|
|
39
41
|
export * from "./components/RadioGroup/RadioGroup";
|
|
40
42
|
export type { ButtonProps } from "./components/Button/Button";
|
|
41
43
|
export type { InputProps } from "./components/TextInput/TextInput";
|
|
44
|
+
export type { MaskedTextInputProps, MaskRule, } from "./components/MaskedTextInput";
|
|
42
45
|
export type { NumberInputProps } from "./components/NumberInput/NumberInput";
|
|
43
46
|
export type { TextAreaProps } from "./components/TextArea/TextArea";
|
|
44
47
|
export type { DropdownProps, Options } from "./components/Dropdown/Dropdown";
|
|
@@ -10,14 +10,15 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
13
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, Fragment, } from "react";
|
|
14
14
|
import * as Portal from "@radix-ui/react-portal";
|
|
15
15
|
import TextInput from "../TextInput/TextInput";
|
|
16
16
|
import { customInputVariant, dropdownIconVariant } from "./Dropdown.styles";
|
|
17
|
+
import { Menu } from "../Menu/Menu";
|
|
17
18
|
import { ChevronDownIcon } from "@heroicons/react/16/solid";
|
|
18
19
|
import { cn } from "@/utils/cn";
|
|
19
20
|
const Dropdown = forwardRef((_a, ref) => {
|
|
20
|
-
var { id, options = [], value, label, size = "md", rounded = "normal", variant = "outline", helperText, errorMessage, fullwidth = true, disabled = false, error = false, filterMode = false, required = true, modal = false, onChangeText, onSelect, renderOptions: customRenderOptions, optionContainerClassName, optionItemClassName, optionNotFoundItemClassName } = _a, props = __rest(_a, ["id", "options", "value", "label", "size", "rounded", "variant", "helperText", "errorMessage", "fullwidth", "disabled", "error", "filterMode", "required", "modal", "onChangeText", "onSelect", "renderOptions", "optionContainerClassName", "optionItemClassName", "optionNotFoundItemClassName"]);
|
|
21
|
+
var { id, options = [], value, label, size = "md", rounded = "normal", variant = "outline", defaultMenuItemType = "checkbox", helperText, errorMessage, fullwidth = true, disabled = false, error = false, filterMode = false, required = true, modal = false, onChangeText, onSelect, renderOptions: customRenderOptions, optionContainerClassName, optionItemClassName, optionNotFoundItemClassName } = _a, props = __rest(_a, ["id", "options", "value", "label", "size", "rounded", "variant", "defaultMenuItemType", "helperText", "errorMessage", "fullwidth", "disabled", "error", "filterMode", "required", "modal", "onChangeText", "onSelect", "renderOptions", "optionContainerClassName", "optionItemClassName", "optionNotFoundItemClassName"]);
|
|
21
22
|
const _id = id || `${label}-select`;
|
|
22
23
|
const [isFocused, setIsFocused] = useState(false);
|
|
23
24
|
const [selectedOption, setSelectedOption] = useState(null);
|
|
@@ -116,23 +117,44 @@ const Dropdown = forwardRef((_a, ref) => {
|
|
|
116
117
|
dropdownRef,
|
|
117
118
|
});
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
120
|
+
// Convert options to MenuItemType
|
|
121
|
+
let finalMenuItems;
|
|
122
|
+
finalMenuItems = optionsFiltered.map((option) => {
|
|
123
|
+
if (option.renderLabel) {
|
|
124
|
+
return {
|
|
125
|
+
type: "custom",
|
|
126
|
+
render: () => (_jsx(Fragment, { children: option.renderLabel({
|
|
127
|
+
value: option.value,
|
|
128
|
+
label: option.label,
|
|
129
|
+
handleOnClick: () => handleOptionClick(option),
|
|
130
|
+
className: cn("relative flex gap-3 cursor-pointer select-none box-border items-center py-4 pl-9 pr-4 typography-subtitile4 outline-none transition-colors", "bg-[var(--dropdown-menu-default-bg)] text-[var(--dropdown-menu-default-text)]", "active:opacity-75", "hover:bg-[var(--dropdown-menu-hover-bg)] hover:text-[var(--dropdown-menu-hover-text)]", {
|
|
131
|
+
"bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)] typography-subtitile5": (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) === option.value,
|
|
132
|
+
}, optionItemClassName),
|
|
133
|
+
}) }, option.value)),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
type: "item",
|
|
138
|
+
item: {
|
|
139
|
+
type: defaultMenuItemType,
|
|
140
|
+
value: option.value,
|
|
141
|
+
label: option.label,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
// Add "not found" message if no results
|
|
146
|
+
if (finalMenuItems.length === 0) {
|
|
147
|
+
finalMenuItems.push({
|
|
148
|
+
type: "custom",
|
|
149
|
+
render: () => (_jsx("div", { className: cn("px-4 py-14 text-center text-input-text", optionNotFoundItemClassName), children: "Not found" }, "not-found")),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return (_jsx(Menu, { ref: dropdownRef, items: finalMenuItems, selectedValues: (selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value) ? [selectedOption.value] : [], onSelect: (value) => {
|
|
153
|
+
const option = optionsFiltered.find((opt) => opt.value === value);
|
|
154
|
+
if (option) {
|
|
155
|
+
handleOptionClick(option);
|
|
156
|
+
}
|
|
157
|
+
}, className: cn("absolute mt-1 w-full max-h-60 overflow-y-auto", !usePortal && (isAbove ? "bottom-full mb-1" : "top-full mt-1"), optionContainerClassName), style: dropdownStyles }));
|
|
136
158
|
};
|
|
137
159
|
const handleOnFocus = useCallback((e) => {
|
|
138
160
|
var _a;
|
|
@@ -100,3 +100,16 @@ export const CustomOption = {
|
|
|
100
100
|
return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Dropdown, Object.assign({ id: "1", size: "lg", options: options }, args, { onChangeText: onChangeText })) }));
|
|
101
101
|
},
|
|
102
102
|
};
|
|
103
|
+
// ==================== Advanced Menu Features ====================
|
|
104
|
+
export const WithIcons = {
|
|
105
|
+
render: () => {
|
|
106
|
+
const [selectedValue, setSelectedValue] = useState();
|
|
107
|
+
const optionsWithIcons = [
|
|
108
|
+
{ value: "apple", label: "🍎 Apple" },
|
|
109
|
+
{ value: "banana", label: "🍌 Banana" },
|
|
110
|
+
{ value: "carrot", label: "🥕 Carrot" },
|
|
111
|
+
{ value: "broccoli", label: "🥦 Broccoli" },
|
|
112
|
+
];
|
|
113
|
+
return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx(Dropdown, { id: "with-icons", size: "lg", label: "Select Food", fullwidth: true, options: optionsWithIcons, value: selectedValue, onSelect: (option) => setSelectedValue(option) }) }));
|
|
114
|
+
},
|
|
115
|
+
};
|