automoby-kit 1.0.2 → 1.0.4

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 (82) hide show
  1. package/dist/cjs/Accordion.js +1 -0
  2. package/dist/cjs/Backdrop.js +1 -0
  3. package/dist/cjs/Breadcrumb.js +1 -0
  4. package/dist/cjs/Button.js +1 -0
  5. package/dist/cjs/Chips.js +1 -0
  6. package/dist/cjs/Divider.js +1 -0
  7. package/dist/cjs/Drawer.js +1 -0
  8. package/dist/cjs/Input.js +1 -0
  9. package/dist/cjs/Menu.js +1 -0
  10. package/dist/cjs/Pagination.js +1 -0
  11. package/dist/cjs/ProtectedComponent.js +1 -0
  12. package/dist/cjs/RadioGroup.js +1 -0
  13. package/dist/cjs/Tabs.js +1 -0
  14. package/dist/cjs/Typography.js +1 -0
  15. package/dist/cjs/chunks/MobileContext-Cmx8hQxY.js +1 -0
  16. package/dist/cjs/chunks/chevron-left-Do__K6cA.js +1 -0
  17. package/dist/cjs/chunks/createLucideIcon-BqJVOzoK.js +1 -0
  18. package/dist/cjs/chunks/jsx-runtime-Bgd4cJfV.js +1 -0
  19. package/dist/cjs/contexts.js +1 -0
  20. package/dist/cjs/index.js +1 -0
  21. package/dist/cjs/licensing.js +1 -0
  22. package/dist/cjs/utils.js +1 -0
  23. package/dist/esm/Accordion.js +1 -0
  24. package/dist/esm/Backdrop.js +1 -0
  25. package/dist/esm/Breadcrumb.js +1 -0
  26. package/dist/esm/Button.js +1 -0
  27. package/dist/esm/Chips.js +1 -0
  28. package/dist/esm/Divider.js +1 -0
  29. package/dist/esm/Drawer.js +1 -0
  30. package/dist/esm/Input.js +1 -0
  31. package/dist/esm/Menu.js +1 -0
  32. package/dist/esm/Pagination.js +1 -0
  33. package/dist/esm/ProtectedComponent.js +1 -0
  34. package/dist/esm/RadioGroup.js +1 -0
  35. package/dist/esm/Tabs.js +1 -0
  36. package/dist/esm/Typography.js +1 -0
  37. package/dist/esm/chunks/MobileContext-BtGMRo2b.js +1 -0
  38. package/dist/esm/chunks/chevron-left-4HSuTes3.js +1 -0
  39. package/dist/esm/chunks/createLucideIcon-DGp0SoUT.js +1 -0
  40. package/dist/esm/chunks/jsx-runtime-DZXOD2H9.js +1 -0
  41. package/dist/esm/contexts.js +1 -0
  42. package/dist/esm/index.js +1 -0
  43. package/dist/esm/licensing.js +1 -0
  44. package/dist/esm/utils.js +1 -0
  45. package/dist/types/Accordion.js +54 -0
  46. package/dist/types/Backdrop.js +24 -0
  47. package/dist/types/Breadcrumb.js +56 -0
  48. package/dist/types/Button.js +46 -0
  49. package/dist/types/Chips.js +109 -0
  50. package/dist/types/Divider.js +21 -0
  51. package/dist/types/Drawer.js +107 -0
  52. package/dist/types/Input.js +78 -0
  53. package/dist/types/Menu.js +120 -0
  54. package/dist/{index.esm.js → types/MobileContext-D-Cbqeno.js} +3 -1519
  55. package/dist/types/Pagination.js +183 -0
  56. package/dist/types/ProtectedComponent.js +33 -0
  57. package/dist/types/RadioGroup.js +68 -0
  58. package/dist/types/Tabs.js +49 -0
  59. package/dist/types/Typography.js +60 -0
  60. package/dist/types/chevron-left-Ck6O99eF.js +14 -0
  61. package/dist/types/components/Accordion/Accordion.d.ts +2 -2
  62. package/dist/types/components/Accordion/Accordion.stories.d.ts +10 -9
  63. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +4 -1
  64. package/dist/types/components/Breadcrumb/Breadcrumb.stories.d.ts +4 -3
  65. package/dist/types/components/Chips/Chips.d.ts +2 -2
  66. package/dist/types/components/Drawer/Drawer.d.ts +4 -0
  67. package/dist/types/components/Drawer/Drawer.stories.d.ts +21 -8
  68. package/dist/types/components/Input/Input.d.ts +8 -0
  69. package/dist/types/components/Input/Input.stories.d.ts +1 -0
  70. package/dist/types/components/Pagination/Pagination.d.ts +4 -0
  71. package/dist/types/components/Pagination/Pagination.stories.d.ts +17 -2
  72. package/dist/types/components/RadioGroup/RadioGroup.d.ts +2 -2
  73. package/dist/types/components/Tabs/Tabs.d.ts +2 -2
  74. package/dist/types/contexts.js +3 -0
  75. package/dist/types/createLucideIcon-D-q73LTT.js +112 -0
  76. package/dist/types/index.d.ts +3 -0
  77. package/dist/types/index.js +38 -0
  78. package/dist/types/jsx-runtime-BiC2V0nk.js +430 -0
  79. package/dist/types/licensing.js +125 -0
  80. package/dist/types/utils.js +7 -0
  81. package/package.json +93 -4
  82. package/dist/index.cjs.js +0 -3019
@@ -0,0 +1,54 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React, { useState } from 'react';
3
+ import cn from './utils.js';
4
+ import { Typography } from './Typography.js';
5
+ import { c as createLucideIcon } from './createLucideIcon-D-q73LTT.js';
6
+
7
+ /**
8
+ * @license lucide-react v0.522.0 - ISC
9
+ *
10
+ * This source code is licensed under the ISC license.
11
+ * See the LICENSE file in the root directory of this source tree.
12
+ */
13
+
14
+
15
+ const __iconNode$1 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
16
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1);
17
+
18
+ /**
19
+ * @license lucide-react v0.522.0 - ISC
20
+ *
21
+ * This source code is licensed under the ISC license.
22
+ * See the LICENSE file in the root directory of this source tree.
23
+ */
24
+
25
+
26
+ const __iconNode = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
27
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode);
28
+
29
+ const Accordion = React.forwardRef(({ title, body, startIcon, isExpanded: controlledExpanded, onToggle, defaultExpanded = false, className, id, disabled = false, isMobile, ...props }, ref) => {
30
+ const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
31
+ // Use controlled state if provided, otherwise use internal state
32
+ const isExpanded = controlledExpanded !== undefined ? controlledExpanded : internalExpanded;
33
+ const handleToggle = () => {
34
+ if (disabled)
35
+ return;
36
+ const newExpanded = !isExpanded;
37
+ if (controlledExpanded === undefined) {
38
+ setInternalExpanded(newExpanded);
39
+ }
40
+ onToggle?.(newExpanded);
41
+ };
42
+ const accordionId = id || `accordion-${Math.random().toString(36).substr(2, 9)}`;
43
+ const headerId = `${accordionId}-header`;
44
+ const contentId = `${accordionId}-content`;
45
+ // Icon size based on device
46
+ const iconSize = isMobile ? 20 : 24;
47
+ // Typography variants based on device
48
+ const titleVariant = isMobile ? 'body-s-heavy' : 'body-l-heavy';
49
+ const bodyVariant = isMobile ? 'body-s-medium' : 'body-m-medium';
50
+ return (jsxRuntimeExports.jsxs("div", { ref: ref, className: cn('rounded-2xl border-0 overflow-hidden', 'transition-all duration-200 ease-in-out', className), ...props, children: [jsxRuntimeExports.jsxs("button", { id: headerId, type: "button", onClick: handleToggle, disabled: disabled, "aria-expanded": isExpanded, "aria-controls": contentId, className: cn('w-full flex items-center justify-between', isMobile ? 'p-3' : 'p-4', 'focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2', 'disabled:opacity-50 disabled:cursor-not-allowed', 'transition-all duration-200 ease-in-out', !disabled && 'hover:bg-neutral-lighter'), children: [jsxRuntimeExports.jsx("div", { className: "flex-shrink-0 mr-4", children: isExpanded ? (jsxRuntimeExports.jsx(ChevronUp, { size: iconSize, className: "text-neutral-darker transition-transform duration-200", "aria-hidden": "true" })) : (jsxRuntimeExports.jsx(ChevronDown, { size: iconSize, className: "text-neutral-darker transition-transform duration-200", "aria-hidden": "true" })) }), jsxRuntimeExports.jsxs("div", { className: cn('flex items-center flex-1', isMobile ? 'gap-3' : 'gap-4'), children: [jsxRuntimeExports.jsx("div", { className: "flex-1 text-right", children: jsxRuntimeExports.jsx(Typography, { variant: titleVariant, color: "neutral-darker", children: title }) }), startIcon && (jsxRuntimeExports.jsx("div", { className: cn('flex-shrink-0 flex items-center justify-center', isMobile ? 'w-6 h-6' : 'w-8 h-8'), children: startIcon }))] })] }), jsxRuntimeExports.jsx("div", { id: contentId, role: "region", "aria-labelledby": headerId, className: cn('w-full overflow-hidden transition-all duration-300 ease-in-out', isExpanded ? 'max-h-screen opacity-100' : 'max-h-0 opacity-0'), children: jsxRuntimeExports.jsx("div", { className: cn(isMobile ? 'pb-3 mt-1' : 'pb-4 mt-1.5'), children: jsxRuntimeExports.jsx("div", { className: cn('bg-neutral-lighter rounded-lg', isMobile ? 'p-3' : 'p-4'), children: jsxRuntimeExports.jsx(Typography, { variant: bodyVariant, color: "neutral-dark", children: body }) }) }) })] }));
51
+ });
52
+ Accordion.displayName = 'Accordion';
53
+
54
+ export { Accordion };
@@ -0,0 +1,24 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React from 'react';
3
+ import cn from './utils.js';
4
+
5
+ const Backdrop = React.forwardRef(({ isOpen = false, onClick, blur = false, zIndex = 51, className, children, ...props }, ref) => {
6
+ const handleClick = (event) => {
7
+ if (onClick && event.target === event.currentTarget) {
8
+ onClick();
9
+ }
10
+ };
11
+ const backdropClasses = cn('fixed inset-0 transition-all duration-300', {
12
+ 'opacity-100 pointer-events-auto': isOpen,
13
+ 'opacity-0 pointer-events-none': !isOpen,
14
+ 'backdrop-blur-sm': blur,
15
+ }, className);
16
+ const backdropStyle = {
17
+ backgroundColor: 'rgba(0, 0, 0, 0.60)',
18
+ zIndex,
19
+ };
20
+ return (jsxRuntimeExports.jsx("div", { ref: ref, className: backdropClasses, style: backdropStyle, onClick: handleClick, role: "presentation", "aria-hidden": !isOpen, ...props, children: children }));
21
+ });
22
+ Backdrop.displayName = 'Backdrop';
23
+
24
+ export { Backdrop };
@@ -0,0 +1,56 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React from 'react';
3
+ import cn from './utils.js';
4
+ import { C as ChevronLeft } from './chevron-left-Ck6O99eF.js';
5
+ import './createLucideIcon-D-q73LTT.js';
6
+
7
+ const Breadcrumb = React.forwardRef(({ items, className, isMobile }, ref) => {
8
+ const handleItemClick = (item, index, e) => {
9
+ // Don't make the last item (current page) clickable
10
+ if (index === items.length - 1)
11
+ return;
12
+ if (item.onClick) {
13
+ e.preventDefault();
14
+ item.onClick();
15
+ }
16
+ // If item has href, let the anchor tag handle navigation naturally
17
+ };
18
+ return (jsxRuntimeExports.jsx("nav", { ref: ref, className: cn(
19
+ // Base layout - RTL with flex-row-reverse to show items right to left
20
+ 'flex flex-row-reverse items-center',
21
+ // Responsive gap and padding based on mobile state
22
+ isMobile ? 'gap-1 px-4 py-2.5' : 'gap-3 pr-1 pt-3 pb-4 pl-0', className), "aria-label": "Breadcrumb navigation", children: jsxRuntimeExports.jsx("ol", { className: "flex flex-row-reverse items-center gap-inherit", children: items.map((item, index) => {
23
+ const isLast = index === items.length - 1;
24
+ const isClickable = !isLast && (item.href || item.onClick);
25
+ const itemKey = `${item.label}-${index}`;
26
+ return (jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-inherit", children: [isClickable ? (jsxRuntimeExports.jsx("a", { href: item.href || '#', className: cn(
27
+ // Base styles
28
+ 'whitespace-nowrap border-0 bg-transparent p-0 no-underline',
29
+ // Responsive font size based on mobile state
30
+ isMobile ? 'text-t' : 'text-s',
31
+ // Color
32
+ 'text-neutral-main',
33
+ // Cursor and hover effects for clickable items
34
+ 'cursor-pointer hover:text-neutral-dark transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1 rounded-sm'), onClick: (e) => handleItemClick(item, index, e), onKeyDown: (e) => {
35
+ if (e.key === 'Enter' || e.key === ' ') {
36
+ e.preventDefault();
37
+ if (item.onClick) {
38
+ item.onClick();
39
+ }
40
+ }
41
+ }, "aria-label": `Go to ${item.label}`, children: item.label })) : (jsxRuntimeExports.jsx("span", { className: cn(
42
+ // Base styles
43
+ 'whitespace-nowrap',
44
+ // Responsive font size based on mobile state
45
+ isMobile ? 'text-t' : 'text-s',
46
+ // Color
47
+ 'text-neutral-main',
48
+ // Different styles for current page (last item)
49
+ 'font-medium'), "aria-current": isLast ? 'page' : undefined, "aria-label": isLast ? `Current page: ${item.label}` : undefined, children: item.label })), !isLast && (jsxRuntimeExports.jsx(ChevronLeft, { className: cn('text-black flex-shrink-0',
50
+ // Responsive icon size
51
+ isMobile ? 'w-2.5 h-2.5' : 'w-3 h-3'), "aria-hidden": "true" }))] }, itemKey));
52
+ }) }) }));
53
+ });
54
+ Breadcrumb.displayName = 'Breadcrumb';
55
+
56
+ export { Breadcrumb };
@@ -0,0 +1,46 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React from 'react';
3
+ import cn from './utils.js';
4
+ import { getTypographyClasses } from './Typography.js';
5
+
6
+ const sizeClasses = {
7
+ sm: 'px-[16px] py-[7px]',
8
+ md: 'px-[16px] py-[9px]',
9
+ lg: 'px-[16px] py-[13px]',
10
+ xl: 'px-[20px] py-[13px]',
11
+ };
12
+ const defaultTextVariants = {
13
+ sm: 'body-s-bold', // 14px / Bold (600)
14
+ md: 'body-m-bold', // 16px / Bold (600)
15
+ lg: 'body-l-bold', // 18px / Bold (600)
16
+ xl: 'body-xl-heavy', // 20px / Heavy (700)
17
+ };
18
+ const variantClasses = {
19
+ primary: `
20
+ bg-[var(--color-primary)] text-white
21
+ hover:bg-[var(--color-primary-dark)]
22
+ disabled:bg-[var(--color-neutral-light)] disabled:text-[var(--color-neutral-darker)]
23
+ `,
24
+ secondary: `
25
+ bg-[var(--color-primary-lightest)] text-[var(--color-primary)]
26
+ hover:bg-[var(--color-primary-lighter)]
27
+ disabled:bg-[var(--color-neutral-light)] disabled:text-[var(--color-neutral-darker)]
28
+ `,
29
+ tertiary: `
30
+ bg-white border border-[var(--color-primary-light)] text-[var(--color-primary)]
31
+ hover:bg-[var(--color-neutral-lighter)]
32
+ disabled:bg-[var(--color-neutral-light)] disabled:text-[var(--color-neutral-darker)]
33
+ `,
34
+ ghost: `
35
+ bg-transparent text-[var(--color-primary)]
36
+ hover:bg-[var(--color-primary-lightest)]
37
+ disabled:bg-[var(--color-neutral-light)] disabled:text-[var(--color-neutral-darker)]
38
+ `,
39
+ };
40
+ const Button = React.forwardRef(({ className, variant = 'primary', size = 'md', icon, iconPosition = 'right', children, loading = false, disabled, textVariant, ...props }, ref) => {
41
+ const finalTextVariant = textVariant || defaultTextVariants[size];
42
+ return (jsxRuntimeExports.jsxs("button", { ref: ref, type: "button", className: cn('inline-flex items-center justify-center rounded-[8px] transition-colors duration-200', sizeClasses[size], variantClasses[variant], getTypographyClasses(finalTextVariant), disabled && 'opacity-50 pointer-events-none', className), disabled: disabled || loading, ...props, children: [icon && iconPosition === 'left' && (jsxRuntimeExports.jsx("span", { className: "mr-2 flex items-center", children: icon })), loading ? '...' : children, icon && iconPosition === 'right' && (jsxRuntimeExports.jsx("span", { className: "ml-2 flex items-center", children: icon }))] }));
43
+ });
44
+ Button.displayName = 'Button';
45
+
46
+ export { Button };
@@ -0,0 +1,109 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React from 'react';
3
+ import cn from './utils.js';
4
+ import { c as createLucideIcon } from './createLucideIcon-D-q73LTT.js';
5
+
6
+ /**
7
+ * @license lucide-react v0.522.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */
12
+
13
+
14
+ const __iconNode = [
15
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
16
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
17
+ ];
18
+ const X = createLucideIcon("x", __iconNode);
19
+
20
+ const chipVariants = {
21
+ purple: {
22
+ background: 'bg-[var(--color-primary-lightest)]',
23
+ text: 'text-[var(--color-primary-darkest)]',
24
+ border: 'border-[var(--color-primary-light)]',
25
+ },
26
+ red: {
27
+ background: 'bg-[var(--color-error-light)]',
28
+ text: 'text-[var(--color-error)]',
29
+ border: 'border-[#f0d6d6]',
30
+ },
31
+ green: {
32
+ background: 'bg-[var(--color-success-light)]',
33
+ text: 'text-[var(--color-success)]',
34
+ border: 'border-[#d4e8dc]',
35
+ },
36
+ orange: {
37
+ background: 'bg-[var(--color-warning-light)]',
38
+ text: 'text-[var(--color-warning)]',
39
+ border: 'border-[#f5e1d1]',
40
+ },
41
+ blue: {
42
+ background: 'bg-[var(--color-info-light)]',
43
+ text: 'text-[var(--color-info)]',
44
+ border: 'border-[#d3e9f2]',
45
+ },
46
+ white: {
47
+ background: 'bg-[var(--color-white)]',
48
+ text: 'text-[var(--color-neutral-darker)]',
49
+ border: 'border-[var(--color-neutral-light)]',
50
+ },
51
+ disabled: {
52
+ background: 'bg-[var(--color-neutral-lighter)]',
53
+ text: 'text-[var(--color-neutral-main)]',
54
+ border: 'border-[var(--color-neutral-light)]',
55
+ },
56
+ };
57
+ const chipSizes = {
58
+ mobile: {
59
+ padding: 'px-2.5 py-1',
60
+ gap: 'gap-1',
61
+ iconSize: 'size-4',
62
+ fontSize: 'text-[12px]',
63
+ lineHeight: 'leading-[1.8]',
64
+ },
65
+ desktop: {
66
+ padding: 'px-3 py-1',
67
+ gap: 'gap-1.5',
68
+ iconSize: 'size-5',
69
+ fontSize: 'text-[14px]',
70
+ lineHeight: 'leading-[24px]',
71
+ },
72
+ };
73
+ const Chips = React.forwardRef(({ variant = 'purple', size, children = 'متن پیشفرض', disabled = false, onClick, onIconClick, className, isMobile, ...props }, ref) => {
74
+ const actualSize = size || (isMobile ? 'mobile' : 'desktop');
75
+ const actualVariant = disabled ? 'disabled' : variant;
76
+ const variantStyles = chipVariants[actualVariant];
77
+ const sizeStyles = chipSizes[actualSize];
78
+ const handleIconClick = (e) => {
79
+ e.stopPropagation();
80
+ if (onIconClick) {
81
+ onIconClick();
82
+ }
83
+ };
84
+ const handleKeyDown = (e) => {
85
+ if ((e.key === 'Enter' || e.key === ' ') && onClick && !disabled) {
86
+ e.preventDefault();
87
+ onClick();
88
+ }
89
+ };
90
+ const renderIcon = () => {
91
+ const iconElement = jsxRuntimeExports.jsx(X, { className: cn(sizeStyles.iconSize) });
92
+ if (onIconClick) {
93
+ return (jsxRuntimeExports.jsx("button", { type: "button", onClick: handleIconClick, disabled: disabled, className: cn('flex items-center justify-center', 'hover:opacity-70 transition-opacity', disabled && 'cursor-not-allowed opacity-50'), "aria-label": "\u062D\u0630\u0641", children: iconElement }));
94
+ }
95
+ return iconElement;
96
+ };
97
+ return (jsxRuntimeExports.jsxs("div", { ref: ref, className: cn(
98
+ // Base styles
99
+ 'relative rounded-[50px] border border-solid inline-flex', 'flex-row items-center justify-center', 'font-sans font-bold not-italic', 'text-nowrap text-right', 'transition-all duration-200',
100
+ // Variant styles
101
+ variantStyles.background, variantStyles.text, variantStyles.border,
102
+ // Size styles
103
+ sizeStyles.padding, sizeStyles.gap, sizeStyles.fontSize, sizeStyles.lineHeight,
104
+ // Interactive styles
105
+ onClick && !disabled && 'cursor-pointer hover:opacity-80', disabled && 'cursor-not-allowed opacity-60', className), onClick: disabled ? undefined : onClick, onKeyDown: onClick && !disabled ? handleKeyDown : undefined, tabIndex: onClick && !disabled ? 0 : undefined, role: onClick ? 'button' : undefined, ...props, children: [jsxRuntimeExports.jsx("span", { className: "text-center", children: children }), renderIcon()] }));
106
+ });
107
+ Chips.displayName = 'Chips';
108
+
109
+ export { Chips, Chips as default };
@@ -0,0 +1,21 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React from 'react';
3
+ import cn from './utils.js';
4
+
5
+ const Divider = React.forwardRef(({ width = '100%', height = 1, orientation = 'horizontal', variant = 'neutral-light', className, style, ...props }, ref) => {
6
+ const isHorizontal = orientation === 'horizontal';
7
+ const variantClasses = {
8
+ 'neutral-light': 'bg-neutral-light',
9
+ 'neutral-main': 'bg-neutral-main',
10
+ primary: 'bg-primary',
11
+ };
12
+ const dividerStyle = {
13
+ width: isHorizontal ? width : height,
14
+ height: isHorizontal ? height : width,
15
+ ...style,
16
+ };
17
+ return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('shrink-0', variantClasses[variant], className), style: dividerStyle, role: "separator", ...props }));
18
+ });
19
+ Divider.displayName = 'Divider';
20
+
21
+ export { Divider };
@@ -0,0 +1,107 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React, { useRef, useEffect } from 'react';
3
+ import cn from './utils.js';
4
+
5
+ const Drawer = React.forwardRef(({ children, direction = 'bottom', fullScreen = false, isOpen = false, onClose, className, isMobile, ...props }, ref) => {
6
+ const overlayRef = useRef(null);
7
+ const drawerRef = useRef(null);
8
+ // Handle escape key
9
+ useEffect(() => {
10
+ const handleEscape = (event) => {
11
+ if (event.key === 'Escape' && isOpen && onClose) {
12
+ onClose();
13
+ }
14
+ };
15
+ if (isOpen) {
16
+ document.addEventListener('keydown', handleEscape);
17
+ // Prevent body scroll when drawer is open
18
+ document.body.style.overflow = 'hidden';
19
+ }
20
+ return () => {
21
+ document.removeEventListener('keydown', handleEscape);
22
+ document.body.style.overflow = 'auto';
23
+ };
24
+ }, [isOpen, onClose]);
25
+ // Handle click outside
26
+ const handleOverlayClick = (event) => {
27
+ if (!fullScreen &&
28
+ onClose &&
29
+ overlayRef.current &&
30
+ event.target === overlayRef.current) {
31
+ onClose();
32
+ }
33
+ };
34
+ // Handle keyboard events on overlay
35
+ const handleOverlayKeyDown = (event) => {
36
+ if (event.key === 'Enter' || event.key === ' ') {
37
+ if (!fullScreen &&
38
+ onClose &&
39
+ overlayRef.current &&
40
+ event.target === overlayRef.current) {
41
+ onClose();
42
+ }
43
+ }
44
+ };
45
+ const getTranslateClasses = () => {
46
+ if (!isOpen) {
47
+ switch (direction) {
48
+ case 'top':
49
+ return '-translate-y-full';
50
+ case 'bottom':
51
+ return 'translate-y-full';
52
+ case 'left':
53
+ return '-translate-x-full';
54
+ case 'right':
55
+ return 'translate-x-full';
56
+ default:
57
+ return 'translate-y-full';
58
+ }
59
+ }
60
+ return 'translate-x-0 translate-y-0';
61
+ };
62
+ const getPositionClasses = () => {
63
+ switch (direction) {
64
+ case 'top':
65
+ return 'top-0 left-0 right-0';
66
+ case 'bottom':
67
+ return 'bottom-0 left-0 right-0';
68
+ case 'left':
69
+ return 'top-0 left-0 bottom-0';
70
+ case 'right':
71
+ return 'top-0 right-0 bottom-0';
72
+ default:
73
+ return 'bottom-0 left-0 right-0';
74
+ }
75
+ };
76
+ const getSizeClasses = () => {
77
+ const isVertical = direction === 'top' || direction === 'bottom';
78
+ if (fullScreen) {
79
+ return isVertical ? 'w-full h-full' : 'w-full h-full';
80
+ }
81
+ if (isVertical) {
82
+ return 'w-full max-h-[90vh]';
83
+ }
84
+ return 'h-full max-w-[90vw]';
85
+ };
86
+ const baseOverlayClasses = 'fixed inset-0 z-50 transition-all duration-300';
87
+ const baseDrawerClasses = 'fixed bg-white shadow-2xl transition-all duration-300 ease-out overflow-auto';
88
+ const overlayClasses = cn(baseOverlayClasses, {
89
+ 'bg-neutral-darker/50 backdrop-blur-sm': isOpen,
90
+ 'bg-transparent pointer-events-none': !isOpen,
91
+ });
92
+ const drawerClasses = cn(baseDrawerClasses, getPositionClasses(), getSizeClasses(), getTranslateClasses(), {
93
+ 'rounded-t-2xl': direction === 'bottom' && !fullScreen,
94
+ 'rounded-b-2xl': direction === 'top' && !fullScreen,
95
+ 'rounded-r-2xl': direction === 'left' && !fullScreen,
96
+ 'rounded-l-2xl': direction === 'right' && !fullScreen,
97
+ 'p-6': !isMobile,
98
+ 'p-4': isMobile,
99
+ }, className);
100
+ if (!isOpen) {
101
+ return null;
102
+ }
103
+ return (jsxRuntimeExports.jsx("div", { ref: overlayRef, className: overlayClasses, onClick: handleOverlayClick, onKeyDown: handleOverlayKeyDown, tabIndex: -1, role: "button", "aria-label": "Close drawer", children: jsxRuntimeExports.jsx("div", { ref: ref || drawerRef, className: drawerClasses, role: "dialog", "aria-modal": "true", "aria-label": "Drawer", ...props, children: children }) }));
104
+ });
105
+ Drawer.displayName = 'Drawer';
106
+
107
+ export { Drawer };
@@ -0,0 +1,78 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React, { useState, useId } from 'react';
3
+ import cn from './utils.js';
4
+
5
+ const Input = React.forwardRef(({ state = 'default', label, value, onChange, helperText, startIcon, endIcon, type = 'text', isMobile, ...props }, ref) => {
6
+ const [isFocused, setIsFocused] = useState(false);
7
+ const id = useId();
8
+ const hasContent = value !== '' && value !== null && value !== undefined;
9
+ const isLabelFloated = isFocused || hasContent;
10
+ const isDisabled = state === 'disabled';
11
+ const handleFocus = (e) => {
12
+ if (!isDisabled) {
13
+ setIsFocused(true);
14
+ props.onFocus?.(e);
15
+ }
16
+ };
17
+ const handleBlur = (e) => {
18
+ if (!isDisabled) {
19
+ setIsFocused(false);
20
+ props.onBlur?.(e);
21
+ }
22
+ };
23
+ const baseContainerClasses = 'relative flex items-center border rounded-lg transition-all duration-300 w-[360px]';
24
+ const baseLabelClasses = 'absolute pointer-events-none transition-all duration-300';
25
+ const baseInputClasses = 'peer w-full h-full bg-transparent outline-none text-m font-medium disabled:text-neutral-light';
26
+ const baseIconClasses = 'absolute h-5 w-5 transition-colors duration-300';
27
+ const containerClasses = cn(baseContainerClasses, {
28
+ 'h-[54px]': !isMobile,
29
+ 'h-12': isMobile,
30
+ 'border-neutral-light': state === 'default' && !isFocused,
31
+ 'border-primary': state === 'default' && isFocused,
32
+ 'border-error': state === 'error',
33
+ 'bg-white border-neutral-light cursor-not-allowed': isDisabled,
34
+ });
35
+ const labelClasses = cn(baseLabelClasses, {
36
+ 'top-[-10px] bg-white px-1 mx-3 font-medium': isLabelFloated,
37
+ 'text-s': (!isMobile && isLabelFloated) || (isMobile && !isLabelFloated),
38
+ 'text-xs': isMobile && isLabelFloated,
39
+ 'text-m': !isMobile && !isLabelFloated,
40
+ 'right-1': startIcon,
41
+ 'right-3': !startIcon,
42
+ 'top-1/2 -translate-y-1/2 text-m font-medium': !isLabelFloated,
43
+ 'right-11': !isLabelFloated && startIcon,
44
+ 'right-4': !isLabelFloated && !startIcon,
45
+ 'text-neutral-main': !isFocused && state === 'default',
46
+ 'text-neutral-light': isDisabled,
47
+ 'text-primary': isFocused && state === 'default',
48
+ 'text-error': isLabelFloated && state === 'error',
49
+ });
50
+ const inputClasses = cn(baseInputClasses, {
51
+ 'pr-12': startIcon,
52
+ 'pl-12': endIcon,
53
+ 'px-4': !startIcon && !endIcon,
54
+ 'pr-4 pl-12': !startIcon && endIcon,
55
+ 'pl-4 pr-12': startIcon && !endIcon,
56
+ 'cursor-not-allowed text-red-500': isDisabled,
57
+ 'text-neutral-dark': !isFocused,
58
+ 'text-neutral-darker': isFocused,
59
+ });
60
+ const iconClasses = cn(baseIconClasses, {
61
+ 'text-neutral-main': state !== 'error' && !isFocused,
62
+ 'text-primary': state === 'default' && isFocused,
63
+ 'text-error': state === 'error',
64
+ 'text-neutral-light': isDisabled,
65
+ });
66
+ const helperTextClasses = cn('font-light mt-1 px-2 h-4', {
67
+ 'text-s': !isMobile,
68
+ 'text-xs': isMobile,
69
+ 'text-neutral-main': state === 'default',
70
+ 'text-primary': state === 'default' && isFocused,
71
+ 'text-error': state === 'error',
72
+ 'text-neutral-light': isDisabled,
73
+ });
74
+ return (jsxRuntimeExports.jsxs("div", { children: [jsxRuntimeExports.jsxs("div", { className: containerClasses, children: [endIcon && (jsxRuntimeExports.jsx("span", { className: cn(iconClasses, 'left-4'), children: endIcon })), jsxRuntimeExports.jsx("label", { htmlFor: id, className: labelClasses, children: label }), jsxRuntimeExports.jsx("input", { ref: ref, id: id, type: type, value: value, onChange: onChange, onFocus: handleFocus, onBlur: handleBlur, disabled: isDisabled, className: inputClasses, ...props }), startIcon && (jsxRuntimeExports.jsx("span", { className: cn(iconClasses, 'right-4'), children: startIcon }))] }), helperText && jsxRuntimeExports.jsx("p", { className: helperTextClasses, children: helperText })] }));
75
+ });
76
+ Input.displayName = 'Input';
77
+
78
+ export { Input };
@@ -0,0 +1,120 @@
1
+ import { j as jsxRuntimeExports } from './jsx-runtime-BiC2V0nk.js';
2
+ import React, { useState, useRef, useEffect } from 'react';
3
+ import cn from './utils.js';
4
+ import { Typography } from './Typography.js';
5
+
6
+ const Menu = React.forwardRef(({ buttonText, items, disabled = false, className, onOpenChange, isOpen: controlledIsOpen, 'aria-label': ariaLabel, ...props }, ref) => {
7
+ const [internalIsOpen, setInternalIsOpen] = useState(false);
8
+ const menuRef = useRef(null);
9
+ const buttonRef = useRef(null);
10
+ // Use controlled or uncontrolled state
11
+ const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;
12
+ const handleToggle = () => {
13
+ if (disabled)
14
+ return;
15
+ const newIsOpen = !isOpen;
16
+ if (controlledIsOpen === undefined) {
17
+ setInternalIsOpen(newIsOpen);
18
+ }
19
+ onOpenChange?.(newIsOpen);
20
+ };
21
+ const handleItemClick = (item) => {
22
+ if (item.disabled)
23
+ return;
24
+ // Close menu after item click
25
+ if (controlledIsOpen === undefined) {
26
+ setInternalIsOpen(false);
27
+ }
28
+ onOpenChange?.(false);
29
+ // Execute item's onClick if provided
30
+ item.onClick?.();
31
+ };
32
+ // Close menu when clicking outside
33
+ useEffect(() => {
34
+ const handleClickOutside = (event) => {
35
+ if (menuRef.current &&
36
+ !menuRef.current.contains(event.target)) {
37
+ if (controlledIsOpen === undefined) {
38
+ setInternalIsOpen(false);
39
+ }
40
+ onOpenChange?.(false);
41
+ }
42
+ };
43
+ if (isOpen) {
44
+ document.addEventListener('mousedown', handleClickOutside);
45
+ return () => {
46
+ document.removeEventListener('mousedown', handleClickOutside);
47
+ };
48
+ }
49
+ return undefined;
50
+ }, [isOpen, controlledIsOpen, onOpenChange]);
51
+ // Handle keyboard navigation
52
+ const handleKeyDown = (event) => {
53
+ if (disabled)
54
+ return;
55
+ switch (event.key) {
56
+ case 'Escape':
57
+ if (isOpen) {
58
+ event.preventDefault();
59
+ if (controlledIsOpen === undefined) {
60
+ setInternalIsOpen(false);
61
+ }
62
+ onOpenChange?.(false);
63
+ buttonRef.current?.focus();
64
+ }
65
+ break;
66
+ case 'ArrowDown':
67
+ if (!isOpen) {
68
+ event.preventDefault();
69
+ handleToggle();
70
+ }
71
+ break;
72
+ case 'Enter':
73
+ case ' ':
74
+ event.preventDefault();
75
+ handleToggle();
76
+ break;
77
+ }
78
+ };
79
+ const buttonClasses = cn(
80
+ // Base button styles matching Figma design
81
+ 'inline-flex items-center justify-center', 'bg-white border border-[var(--color-neutral-light)]', 'rounded-[6px] px-[16px] py-[13px]', 'transition-colors duration-200',
82
+ // Interactive states
83
+ 'hover:bg-[var(--color-neutral-lighter)]', 'focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] focus:ring-offset-2',
84
+ // Disabled state
85
+ {
86
+ 'opacity-50 cursor-not-allowed': disabled,
87
+ 'cursor-pointer': !disabled,
88
+ });
89
+ const dropdownClasses = cn(
90
+ // Base dropdown styles
91
+ 'absolute top-full left-0 right-0 z-10 mt-[4px]', 'bg-white border border-[var(--color-neutral-light)]', 'rounded-[6px] py-[13px] px-[16px]', 'shadow-lg',
92
+ // Animation
93
+ 'transition-all duration-200', {
94
+ 'opacity-100 translate-y-0 pointer-events-auto': isOpen,
95
+ 'opacity-0 -translate-y-2 pointer-events-none': !isOpen,
96
+ });
97
+ const itemClasses = cn('block w-full text-right', 'transition-colors duration-200', 'hover:bg-[var(--color-neutral-lighter)] rounded-[4px] px-[8px] py-[4px] -mx-[8px]', 'focus:outline-none focus:bg-[var(--color-neutral-lighter)]');
98
+ return (jsxRuntimeExports.jsx("div", { ref: ref, className: cn('relative inline-block', className), ...props, children: jsxRuntimeExports.jsxs("div", { ref: menuRef, children: [jsxRuntimeExports.jsx("button", { ref: buttonRef, type: "button", className: buttonClasses, onClick: handleToggle, onKeyDown: handleKeyDown, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "true", "aria-label": ariaLabel || `منوی ${buttonText}`, children: jsxRuntimeExports.jsx(Typography, { variant: "body-s-heavy", color: "neutral-darker", className: "text-right", children: buttonText }) }), jsxRuntimeExports.jsx("div", { className: dropdownClasses, children: jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-[16px]", children: items.map((item) => {
99
+ const content = (jsxRuntimeExports.jsx(Typography, { variant: "body-s-heavy", color: item.disabled ? 'neutral-main' : 'neutral-darker', className: "text-right", children: item.label }));
100
+ const commonProps = {
101
+ className: cn(itemClasses, {
102
+ 'opacity-50 cursor-not-allowed': item.disabled,
103
+ 'cursor-pointer': !item.disabled,
104
+ }),
105
+ onClick: item.disabled
106
+ ? undefined
107
+ : () => handleItemClick(item),
108
+ 'aria-label': `منوی ${item.label}`,
109
+ };
110
+ // Render as link if href is provided
111
+ if (item.href && !item.disabled) {
112
+ return (jsxRuntimeExports.jsx("a", { ...commonProps, href: item.href, role: "menuitem", tabIndex: isOpen ? 0 : -1, children: content }, item.id));
113
+ }
114
+ // Render as button
115
+ return (jsxRuntimeExports.jsx("button", { ...commonProps, type: "button", role: "menuitem", tabIndex: isOpen ? 0 : -1, disabled: item.disabled, children: content }, item.id));
116
+ }) }) })] }) }));
117
+ });
118
+ Menu.displayName = 'Menu';
119
+
120
+ export { Menu };