@rovula/ui 0.0.78 → 0.0.80
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 +15 -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/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 +1 -0
- package/dist/components/Dropdown/Dropdown.js +41 -19
- package/dist/components/Dropdown/Dropdown.stories.js +13 -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/esm/bundle.css +15 -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/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 +1 -0
- package/dist/index.d.ts +111 -3
- package/dist/index.js +1 -0
- package/dist/src/theme/global.css +20 -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/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/index.ts +1 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { CSSProperties, ReactNode } from "react";
|
|
2
2
|
import { InputProps } from "../TextInput/TextInput";
|
|
3
|
+
import { MenuOption } from "../Menu/Menu";
|
|
3
4
|
type RenderLabelCallbackArg = {
|
|
4
5
|
value: string;
|
|
5
6
|
label: string;
|
|
@@ -17,6 +18,7 @@ export type DropdownProps = {
|
|
|
17
18
|
size?: "sm" | "md" | "lg";
|
|
18
19
|
rounded?: "none" | "normal" | "full";
|
|
19
20
|
variant?: "flat" | "outline" | "underline";
|
|
21
|
+
defaultMenuItemType?: MenuOption["type"];
|
|
20
22
|
helperText?: string;
|
|
21
23
|
errorMessage?: string;
|
|
22
24
|
filterMode?: boolean;
|
|
@@ -47,6 +49,7 @@ declare const Dropdown: React.ForwardRefExoticComponent<{
|
|
|
47
49
|
size?: "sm" | "md" | "lg";
|
|
48
50
|
rounded?: "none" | "normal" | "full";
|
|
49
51
|
variant?: "flat" | "outline" | "underline";
|
|
52
|
+
defaultMenuItemType?: MenuOption["type"];
|
|
50
53
|
helperText?: string;
|
|
51
54
|
errorMessage?: string;
|
|
52
55
|
filterMode?: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import type { StoryObj } from "@storybook/react";
|
|
3
|
+
import Dropdown, { Options } from "./Dropdown";
|
|
3
4
|
declare const meta: {
|
|
4
5
|
title: string;
|
|
5
6
|
component: React.ForwardRefExoticComponent<{
|
|
@@ -8,6 +9,7 @@ declare const meta: {
|
|
|
8
9
|
size?: "sm" | "md" | "lg";
|
|
9
10
|
rounded?: "none" | "normal" | "full";
|
|
10
11
|
variant?: "flat" | "outline" | "underline";
|
|
12
|
+
defaultMenuItemType?: import("../Menu/Menu").MenuOption["type"];
|
|
11
13
|
helperText?: string;
|
|
12
14
|
errorMessage?: string;
|
|
13
15
|
filterMode?: boolean;
|
|
@@ -42,6 +44,7 @@ declare const meta: {
|
|
|
42
44
|
size?: "sm" | "md" | "lg" | undefined;
|
|
43
45
|
rounded?: "none" | "normal" | "full" | undefined;
|
|
44
46
|
variant?: "flat" | "outline" | "underline" | undefined;
|
|
47
|
+
defaultMenuItemType?: "checkbox" | "radio" | "default" | undefined;
|
|
45
48
|
helperText?: string | undefined;
|
|
46
49
|
errorMessage?: string | undefined;
|
|
47
50
|
filterMode?: boolean | undefined;
|
|
@@ -405,3 +408,4 @@ export declare const CustomOption: {
|
|
|
405
408
|
};
|
|
406
409
|
render: (args: {}) => import("react/jsx-runtime").JSX.Element;
|
|
407
410
|
};
|
|
411
|
+
export declare const WithIcons: StoryObj<typeof Dropdown>;
|
|
@@ -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)[];
|
|
@@ -30,6 +30,7 @@ export * from "./components/InputFilter/InputFilter";
|
|
|
30
30
|
export * from "./components/Slider/Slider";
|
|
31
31
|
export * from "./components/Switch/Switch";
|
|
32
32
|
export * from "./components/DropdownMenu/DropdownMenu";
|
|
33
|
+
export * from "./components/Menu/Menu";
|
|
33
34
|
export * from "./components/Tooltip/Tooltip";
|
|
34
35
|
export * from "./components/Tooltip/TooltipSimple";
|
|
35
36
|
export * from "./components/Toast/Toast";
|
package/dist/index.d.ts
CHANGED
|
@@ -298,6 +298,70 @@ type TabsProps = {
|
|
|
298
298
|
};
|
|
299
299
|
declare const Tabs: React__default.FC<TabsProps>;
|
|
300
300
|
|
|
301
|
+
type MenuOption = {
|
|
302
|
+
value: string;
|
|
303
|
+
label: ReactNode;
|
|
304
|
+
/**
|
|
305
|
+
* Visual type - กำหนดว่าจะแสดง icon อะไร
|
|
306
|
+
* - "default": ไม่มี icon (แค่ highlight background)
|
|
307
|
+
* - "checkbox": แสดง ✓ icon
|
|
308
|
+
* - "radio": แสดง ● icon
|
|
309
|
+
*/
|
|
310
|
+
type?: "default" | "checkbox" | "radio";
|
|
311
|
+
icon?: ReactNode;
|
|
312
|
+
disabled?: boolean;
|
|
313
|
+
danger?: boolean;
|
|
314
|
+
checked?: boolean;
|
|
315
|
+
onClick?: () => void;
|
|
316
|
+
};
|
|
317
|
+
type MenuItemType = {
|
|
318
|
+
type: "item";
|
|
319
|
+
item: MenuOption;
|
|
320
|
+
} | {
|
|
321
|
+
type: "separator";
|
|
322
|
+
} | {
|
|
323
|
+
type: "label";
|
|
324
|
+
label: string;
|
|
325
|
+
} | {
|
|
326
|
+
type: "custom";
|
|
327
|
+
render: () => ReactNode;
|
|
328
|
+
};
|
|
329
|
+
type MenuProps = {
|
|
330
|
+
items: MenuItemType[];
|
|
331
|
+
/**
|
|
332
|
+
* Selected values - ใช้กับ type="item"
|
|
333
|
+
*/
|
|
334
|
+
selectedValues?: string[];
|
|
335
|
+
/**
|
|
336
|
+
* Callback เมื่อเลือก item
|
|
337
|
+
* - ถ้า item.type="checkbox" → toggle checked state
|
|
338
|
+
* - ถ้า item.type="radio" → single select (clear others)
|
|
339
|
+
* - ถ้า item.type="default" หรือไม่ระบุ → ตาม selectedValues
|
|
340
|
+
*/
|
|
341
|
+
onSelect?: (value: string, item: MenuOption) => void;
|
|
342
|
+
className?: string;
|
|
343
|
+
style?: CSSProperties;
|
|
344
|
+
isAbove?: boolean;
|
|
345
|
+
};
|
|
346
|
+
declare const Menu: React__default.ForwardRefExoticComponent<MenuProps & React__default.RefAttributes<HTMLDivElement>>;
|
|
347
|
+
type MenuItemProps = {
|
|
348
|
+
option: MenuOption;
|
|
349
|
+
visualType: "default" | "checkbox" | "radio";
|
|
350
|
+
isChecked: boolean;
|
|
351
|
+
onSelect: () => void;
|
|
352
|
+
className?: string;
|
|
353
|
+
};
|
|
354
|
+
declare const MenuItem: React__default.ForwardRefExoticComponent<MenuItemProps & React__default.RefAttributes<HTMLDivElement>>;
|
|
355
|
+
type MenuSeparatorProps = {
|
|
356
|
+
className?: string;
|
|
357
|
+
};
|
|
358
|
+
declare const MenuSeparator: React__default.ForwardRefExoticComponent<MenuSeparatorProps & React__default.RefAttributes<HTMLDivElement>>;
|
|
359
|
+
type MenuLabelProps = {
|
|
360
|
+
children: ReactNode;
|
|
361
|
+
className?: string;
|
|
362
|
+
};
|
|
363
|
+
declare const MenuLabel: React__default.ForwardRefExoticComponent<MenuLabelProps & React__default.RefAttributes<HTMLDivElement>>;
|
|
364
|
+
|
|
301
365
|
type RenderLabelCallbackArg$1 = {
|
|
302
366
|
value: string;
|
|
303
367
|
label: string;
|
|
@@ -315,6 +379,7 @@ type DropdownProps = {
|
|
|
315
379
|
size?: "sm" | "md" | "lg";
|
|
316
380
|
rounded?: "none" | "normal" | "full";
|
|
317
381
|
variant?: "flat" | "outline" | "underline";
|
|
382
|
+
defaultMenuItemType?: MenuOption["type"];
|
|
318
383
|
helperText?: string;
|
|
319
384
|
errorMessage?: string;
|
|
320
385
|
filterMode?: boolean;
|
|
@@ -345,6 +410,7 @@ declare const Dropdown: React__default.ForwardRefExoticComponent<{
|
|
|
345
410
|
size?: "sm" | "md" | "lg";
|
|
346
411
|
rounded?: "none" | "normal" | "full";
|
|
347
412
|
variant?: "flat" | "outline" | "underline";
|
|
413
|
+
defaultMenuItemType?: MenuOption["type"];
|
|
348
414
|
helperText?: string;
|
|
349
415
|
errorMessage?: string;
|
|
350
416
|
filterMode?: boolean;
|
|
@@ -588,8 +654,50 @@ declare const AlertDialogDescription: React.ForwardRefExoticComponent<Omit<Alert
|
|
|
588
654
|
declare const AlertDialogAction: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogActionProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
589
655
|
declare const AlertDialogCancel: React.ForwardRefExoticComponent<Omit<AlertDialogPrimitive.AlertDialogCancelProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
590
656
|
|
|
591
|
-
type SearchProps =
|
|
592
|
-
|
|
657
|
+
type SearchProps = {
|
|
658
|
+
id?: string;
|
|
659
|
+
label?: string;
|
|
660
|
+
size?: "sm" | "md" | "lg";
|
|
661
|
+
rounded?: "none" | "normal" | "full";
|
|
662
|
+
variant?: "flat" | "outline" | "underline";
|
|
663
|
+
helperText?: string;
|
|
664
|
+
errorMessage?: string;
|
|
665
|
+
fullwidth?: boolean;
|
|
666
|
+
disabled?: boolean;
|
|
667
|
+
error?: boolean;
|
|
668
|
+
required?: boolean;
|
|
669
|
+
modal?: boolean;
|
|
670
|
+
className?: string;
|
|
671
|
+
optionContainerClassName?: string;
|
|
672
|
+
optionItemClassName?: string;
|
|
673
|
+
optionNotFoundItemClassName?: string;
|
|
674
|
+
options: Options$1[];
|
|
675
|
+
value?: Options$1;
|
|
676
|
+
onChangeText?: InputProps["onChange"];
|
|
677
|
+
onSelect?: (value: Options$1) => void;
|
|
678
|
+
} & Omit<InputProps, "value" | "onSelect">;
|
|
679
|
+
declare const Search: React__default.ForwardRefExoticComponent<{
|
|
680
|
+
id?: string;
|
|
681
|
+
label?: string;
|
|
682
|
+
size?: "sm" | "md" | "lg";
|
|
683
|
+
rounded?: "none" | "normal" | "full";
|
|
684
|
+
variant?: "flat" | "outline" | "underline";
|
|
685
|
+
helperText?: string;
|
|
686
|
+
errorMessage?: string;
|
|
687
|
+
fullwidth?: boolean;
|
|
688
|
+
disabled?: boolean;
|
|
689
|
+
error?: boolean;
|
|
690
|
+
required?: boolean;
|
|
691
|
+
modal?: boolean;
|
|
692
|
+
className?: string;
|
|
693
|
+
optionContainerClassName?: string;
|
|
694
|
+
optionItemClassName?: string;
|
|
695
|
+
optionNotFoundItemClassName?: string;
|
|
696
|
+
options: Options$1[];
|
|
697
|
+
value?: Options$1;
|
|
698
|
+
onChangeText?: InputProps["onChange"];
|
|
699
|
+
onSelect?: (value: Options$1) => void;
|
|
700
|
+
} & Omit<InputProps, "onSelect" | "value"> & React__default.RefAttributes<HTMLInputElement>>;
|
|
593
701
|
|
|
594
702
|
type RenderLabelCallbackArg = {
|
|
595
703
|
value: string;
|
|
@@ -918,4 +1026,4 @@ declare function usePrevious<T>(value: T): T | undefined;
|
|
|
918
1026
|
|
|
919
1027
|
declare function cn(...inputs: ClassValue[]): string;
|
|
920
1028
|
|
|
921
|
-
export { ActionButton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, type ButtonProps, Calendar, Checkbox, Collapsible, type CustomSliderProps, DataTable, type DataTableProps, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type DropdownProps, FocusedScrollView, Icon, Input, InputFilter, type InputFilterProps, type InputProps, Label, Loading, type MaskRule, MaskedTextInput, type MaskedTextInputProps, Navbar, type NavbarProps, NumberInput, type NumberInputProps, type Options$1 as Options, Popover, PopoverContent, PopoverTrigger, ProgressBar, RadioGroup, RadioGroupItem, Search, type SearchProps, Slider, type SliderProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, Text, TextArea, type TextAreaProps, TextInput, Toast$1 as Toast, ToastAction, type ToastActionElement, ToastClose, ToastDescription, type ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipProvider, TooltipSimple, TooltipTrigger, Tree, type TreeData, TreeItem, type TreeItemProps, type TreeProps, cn, getEndDateOfDay, getStartDateOfDay, getStartEndTimestampOfDay, getTimestampUTC, reducer, resloveTimestamp, toast, usePrevious, useToast };
|
|
1029
|
+
export { ActionButton, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, type ButtonProps, Calendar, Checkbox, Collapsible, type CustomSliderProps, DataTable, type DataTableProps, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, type DropdownProps, FocusedScrollView, Icon, Input, InputFilter, type InputFilterProps, type InputProps, Label, Loading, type MaskRule, MaskedTextInput, type MaskedTextInputProps, Menu, MenuItem, type MenuItemType, MenuLabel, type MenuOption, type MenuProps, MenuSeparator, Navbar, type NavbarProps, NumberInput, type NumberInputProps, type Options$1 as Options, Popover, PopoverContent, PopoverTrigger, ProgressBar, RadioGroup, RadioGroupItem, Search, type SearchProps, Slider, type SliderProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, Text, TextArea, type TextAreaProps, TextInput, Toast$1 as Toast, ToastAction, type ToastActionElement, ToastClose, ToastDescription, type ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tooltip, TooltipArrow, TooltipContent, TooltipProvider, TooltipSimple, TooltipTrigger, Tree, type TreeData, TreeItem, type TreeItemProps, type TreeProps, cn, getEndDateOfDay, getStartDateOfDay, getStartEndTimestampOfDay, getTimestampUTC, reducer, resloveTimestamp, toast, usePrevious, useToast };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export * from "./components/InputFilter/InputFilter";
|
|
|
32
32
|
export * from "./components/Slider/Slider";
|
|
33
33
|
export * from "./components/Switch/Switch";
|
|
34
34
|
export * from "./components/DropdownMenu/DropdownMenu";
|
|
35
|
+
export * from "./components/Menu/Menu";
|
|
35
36
|
export * from "./components/Tooltip/Tooltip";
|
|
36
37
|
export * from "./components/Tooltip/TooltipSimple";
|
|
37
38
|
export * from "./components/Toast/Toast";
|
|
@@ -2344,6 +2344,10 @@ input[type=number] {
|
|
|
2344
2344
|
z-index: 10;
|
|
2345
2345
|
}
|
|
2346
2346
|
|
|
2347
|
+
.z-40 {
|
|
2348
|
+
z-index: 40;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2347
2351
|
.z-50 {
|
|
2348
2352
|
z-index: 50;
|
|
2349
2353
|
}
|
|
@@ -2356,10 +2360,6 @@ input[type=number] {
|
|
|
2356
2360
|
z-index: 100;
|
|
2357
2361
|
}
|
|
2358
2362
|
|
|
2359
|
-
.z-\[9999\] {
|
|
2360
|
-
z-index: 9999;
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
2363
|
.col-span-3 {
|
|
2364
2364
|
grid-column: span 3 / span 3;
|
|
2365
2365
|
}
|
|
@@ -2712,6 +2712,10 @@ input[type=number] {
|
|
|
2712
2712
|
width: 2rem;
|
|
2713
2713
|
}
|
|
2714
2714
|
|
|
2715
|
+
.w-80 {
|
|
2716
|
+
width: 20rem;
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2715
2719
|
.w-\[100px\] {
|
|
2716
2720
|
width: 100px;
|
|
2717
2721
|
}
|
|
@@ -6060,6 +6064,10 @@ input[type=number] {
|
|
|
6060
6064
|
caret-color: color-mix(in srgb, var(--state-color-primary-default) calc(100% * 1), transparent);
|
|
6061
6065
|
}
|
|
6062
6066
|
|
|
6067
|
+
.opacity-50 {
|
|
6068
|
+
opacity: 0.5;
|
|
6069
|
+
}
|
|
6070
|
+
|
|
6063
6071
|
.opacity-60 {
|
|
6064
6072
|
opacity: 0.6;
|
|
6065
6073
|
}
|
|
@@ -6570,6 +6578,10 @@ input[type=number] {
|
|
|
6570
6578
|
border-color: color-mix(in srgb, var(--input-color-active-stroke) calc(100% * var(--tw-border-opacity, 1)), transparent);
|
|
6571
6579
|
}
|
|
6572
6580
|
|
|
6581
|
+
.hover\:bg-\[var\(--dropdown-menu-hover-bg\)\]:hover {
|
|
6582
|
+
background-color: var(--dropdown-menu-hover-bg);
|
|
6583
|
+
}
|
|
6584
|
+
|
|
6573
6585
|
.hover\:bg-action-button-icon-active-hover:hover {
|
|
6574
6586
|
--tw-bg-opacity: 1;
|
|
6575
6587
|
background-color: color-mix(in srgb, var(--action-button-icon-active-hover-bg) calc(100% * var(--tw-bg-opacity, 1)), transparent);
|
|
@@ -6841,6 +6853,10 @@ input[type=number] {
|
|
|
6841
6853
|
fill: color-mix(in srgb, var(--input-color-default-text) calc(100% * 1), transparent);
|
|
6842
6854
|
}
|
|
6843
6855
|
|
|
6856
|
+
.hover\:text-\[var\(--dropdown-menu-hover-text\)\]:hover {
|
|
6857
|
+
color: var(--dropdown-menu-hover-text);
|
|
6858
|
+
}
|
|
6859
|
+
|
|
6844
6860
|
.hover\:text-action-button-icon-active-hover:hover {
|
|
6845
6861
|
--tw-text-opacity: 1;
|
|
6846
6862
|
color: color-mix(in srgb, var(--action-button-icon-active-hover-text) calc(100% * var(--tw-text-opacity, 1)), transparent);
|
package/package.json
CHANGED
|
@@ -3,6 +3,8 @@ import type { Meta, StoryObj } from "@storybook/react";
|
|
|
3
3
|
import Dropdown, { Options } from "./Dropdown";
|
|
4
4
|
import Button from "../Button/Button";
|
|
5
5
|
import { cn } from "@/utils/cn";
|
|
6
|
+
import { MenuItemType } from "../Menu/Menu";
|
|
7
|
+
import Icon from "../Icon/Icon";
|
|
6
8
|
|
|
7
9
|
// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
|
|
8
10
|
const meta = {
|
|
@@ -167,3 +169,32 @@ export const CustomOption = {
|
|
|
167
169
|
);
|
|
168
170
|
},
|
|
169
171
|
} satisfies StoryObj;
|
|
172
|
+
|
|
173
|
+
// ==================== Advanced Menu Features ====================
|
|
174
|
+
|
|
175
|
+
export const WithIcons: StoryObj<typeof Dropdown> = {
|
|
176
|
+
render: () => {
|
|
177
|
+
const [selectedValue, setSelectedValue] = useState<Options | undefined>();
|
|
178
|
+
|
|
179
|
+
const optionsWithIcons: Options[] = [
|
|
180
|
+
{ value: "apple", label: "🍎 Apple" },
|
|
181
|
+
{ value: "banana", label: "🍌 Banana" },
|
|
182
|
+
{ value: "carrot", label: "🥕 Carrot" },
|
|
183
|
+
{ value: "broccoli", label: "🥦 Broccoli" },
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<div className="flex flex-row gap-4 w-full">
|
|
188
|
+
<Dropdown
|
|
189
|
+
id="with-icons"
|
|
190
|
+
size="lg"
|
|
191
|
+
label="Select Food"
|
|
192
|
+
fullwidth
|
|
193
|
+
options={optionsWithIcons}
|
|
194
|
+
value={selectedValue}
|
|
195
|
+
onSelect={(option) => setSelectedValue(option)}
|
|
196
|
+
/>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
},
|
|
200
|
+
};
|