sevatech-library 1.0.1 → 1.0.2

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 (136) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/index.js +1568 -23
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/components/avatar/avatar-group.component.d.ts +1 -1
  5. package/dist/cjs/types/components/avatar/avatar-group.component.d.ts.map +1 -1
  6. package/dist/cjs/types/components/avatar/avatar-label-group.component.d.ts +1 -1
  7. package/dist/cjs/types/components/avatar/avatar-label-group.component.d.ts.map +1 -1
  8. package/dist/cjs/types/components/avatar/avatar-profile.component.d.ts +1 -1
  9. package/dist/cjs/types/components/avatar/avatar-profile.component.d.ts.map +1 -1
  10. package/dist/cjs/types/components/avatar/avatar-user.component.d.ts +1 -1
  11. package/dist/cjs/types/components/avatar/avatar-user.component.d.ts.map +1 -1
  12. package/dist/cjs/types/components/avatar/index.d.ts +4 -4
  13. package/dist/cjs/types/components/avatar/index.d.ts.map +1 -1
  14. package/dist/cjs/types/components/bread-crumbs/bread-crumbs.component.d.ts +1 -1
  15. package/dist/cjs/types/components/bread-crumbs/bread-crumbs.component.d.ts.map +1 -1
  16. package/dist/cjs/types/components/button-bar/button-bar.component.d.ts +1 -1
  17. package/dist/cjs/types/components/button-bar/button-bar.component.d.ts.map +1 -1
  18. package/dist/cjs/types/components/checkbox/checkbox-content.component.d.ts.map +1 -1
  19. package/dist/cjs/types/components/checkbox/checkbox.component.d.ts +1 -1
  20. package/dist/cjs/types/components/checkbox/checkbox.component.d.ts.map +1 -1
  21. package/dist/cjs/types/components/chip/chip.component.d.ts +1 -1
  22. package/dist/cjs/types/components/chip/chip.component.d.ts.map +1 -1
  23. package/dist/cjs/types/components/date-field/date-field.component.d.ts +1 -1
  24. package/dist/cjs/types/components/date-field/date-field.component.d.ts.map +1 -1
  25. package/dist/cjs/types/components/date-range-picker/date-range-picker.component.d.ts +1 -1
  26. package/dist/cjs/types/components/date-range-picker/date-range-picker.component.d.ts.map +1 -1
  27. package/dist/cjs/types/components/dropdown-field/dropdown-field.component.d.ts +1 -1
  28. package/dist/cjs/types/components/dropdown-field/dropdown-field.component.d.ts.map +1 -1
  29. package/dist/cjs/types/components/grid/grid.component.d.ts +1 -1
  30. package/dist/cjs/types/components/grid/grid.component.d.ts.map +1 -1
  31. package/dist/cjs/types/components/input-stepper/input-stepper-skeleton.d.ts +1 -1
  32. package/dist/cjs/types/components/input-stepper/input-stepper-skeleton.d.ts.map +1 -1
  33. package/dist/cjs/types/components/input-stepper/input-stepper.component.d.ts +1 -1
  34. package/dist/cjs/types/components/input-stepper/input-stepper.component.d.ts.map +1 -1
  35. package/dist/cjs/types/components/link-field/link-field.component.d.ts +1 -1
  36. package/dist/cjs/types/components/link-field/link-field.component.d.ts.map +1 -1
  37. package/dist/cjs/types/components/modal/index.d.ts +2 -2
  38. package/dist/cjs/types/components/modal/index.d.ts.map +1 -1
  39. package/dist/cjs/types/components/modal/modal-card.component.d.ts +1 -1
  40. package/dist/cjs/types/components/modal/modal-card.component.d.ts.map +1 -1
  41. package/dist/cjs/types/components/modal/modal.component.d.ts +1 -1
  42. package/dist/cjs/types/components/modal/modal.component.d.ts.map +1 -1
  43. package/dist/cjs/types/components/money-field/money-field.component.d.ts +1 -1
  44. package/dist/cjs/types/components/money-field/money-field.component.d.ts.map +1 -1
  45. package/dist/cjs/types/components/phone-number-field/phone-number-field.component.d.ts +1 -1
  46. package/dist/cjs/types/components/phone-number-field/phone-number-field.component.d.ts.map +1 -1
  47. package/dist/cjs/types/components/pin/pin.component.d.ts +1 -1
  48. package/dist/cjs/types/components/pin/pin.component.d.ts.map +1 -1
  49. package/dist/cjs/types/components/search-dropdown/search-dropdown.component.d.ts +1 -1
  50. package/dist/cjs/types/components/search-dropdown/search-dropdown.component.d.ts.map +1 -1
  51. package/dist/cjs/types/components/search-field/search-field.component.d.ts +1 -1
  52. package/dist/cjs/types/components/search-field/search-field.component.d.ts.map +1 -1
  53. package/dist/cjs/types/components/switch/switch-content.component.d.ts +1 -1
  54. package/dist/cjs/types/components/switch/switch-content.component.d.ts.map +1 -1
  55. package/dist/cjs/types/components/switch/switch.component.d.ts +1 -1
  56. package/dist/cjs/types/components/switch/switch.component.d.ts.map +1 -1
  57. package/dist/cjs/types/components/tab/tab.component.d.ts +1 -1
  58. package/dist/cjs/types/components/tab/tab.component.d.ts.map +1 -1
  59. package/dist/cjs/types/components/text-area/text-area.component.d.ts +1 -1
  60. package/dist/cjs/types/components/text-area/text-area.component.d.ts.map +1 -1
  61. package/dist/cjs/types/components/text-field/text-field.component.d.ts +1 -1
  62. package/dist/cjs/types/components/text-field/text-field.component.d.ts.map +1 -1
  63. package/dist/cjs/types/components/typography/typography-limit-one-line.component.d.ts +1 -1
  64. package/dist/cjs/types/components/typography/typography-limit-one-line.component.d.ts.map +1 -1
  65. package/dist/cjs/types/components/uploader/uploader-item.component.d.ts +1 -1
  66. package/dist/cjs/types/components/uploader/uploader-item.component.d.ts.map +1 -1
  67. package/dist/cjs/types/components/uploader/uploader.component.d.ts +1 -1
  68. package/dist/cjs/types/components/uploader/uploader.component.d.ts.map +1 -1
  69. package/dist/esm/index.js +1551 -26
  70. package/dist/esm/index.js.map +1 -1
  71. package/dist/esm/types/components/avatar/avatar-group.component.d.ts +1 -1
  72. package/dist/esm/types/components/avatar/avatar-group.component.d.ts.map +1 -1
  73. package/dist/esm/types/components/avatar/avatar-label-group.component.d.ts +1 -1
  74. package/dist/esm/types/components/avatar/avatar-label-group.component.d.ts.map +1 -1
  75. package/dist/esm/types/components/avatar/avatar-profile.component.d.ts +1 -1
  76. package/dist/esm/types/components/avatar/avatar-profile.component.d.ts.map +1 -1
  77. package/dist/esm/types/components/avatar/avatar-user.component.d.ts +1 -1
  78. package/dist/esm/types/components/avatar/avatar-user.component.d.ts.map +1 -1
  79. package/dist/esm/types/components/avatar/index.d.ts +4 -4
  80. package/dist/esm/types/components/avatar/index.d.ts.map +1 -1
  81. package/dist/esm/types/components/bread-crumbs/bread-crumbs.component.d.ts +1 -1
  82. package/dist/esm/types/components/bread-crumbs/bread-crumbs.component.d.ts.map +1 -1
  83. package/dist/esm/types/components/button-bar/button-bar.component.d.ts +1 -1
  84. package/dist/esm/types/components/button-bar/button-bar.component.d.ts.map +1 -1
  85. package/dist/esm/types/components/checkbox/checkbox-content.component.d.ts.map +1 -1
  86. package/dist/esm/types/components/checkbox/checkbox.component.d.ts +1 -1
  87. package/dist/esm/types/components/checkbox/checkbox.component.d.ts.map +1 -1
  88. package/dist/esm/types/components/chip/chip.component.d.ts +1 -1
  89. package/dist/esm/types/components/chip/chip.component.d.ts.map +1 -1
  90. package/dist/esm/types/components/date-field/date-field.component.d.ts +1 -1
  91. package/dist/esm/types/components/date-field/date-field.component.d.ts.map +1 -1
  92. package/dist/esm/types/components/date-range-picker/date-range-picker.component.d.ts +1 -1
  93. package/dist/esm/types/components/date-range-picker/date-range-picker.component.d.ts.map +1 -1
  94. package/dist/esm/types/components/dropdown-field/dropdown-field.component.d.ts +1 -1
  95. package/dist/esm/types/components/dropdown-field/dropdown-field.component.d.ts.map +1 -1
  96. package/dist/esm/types/components/grid/grid.component.d.ts +1 -1
  97. package/dist/esm/types/components/grid/grid.component.d.ts.map +1 -1
  98. package/dist/esm/types/components/input-stepper/input-stepper-skeleton.d.ts +1 -1
  99. package/dist/esm/types/components/input-stepper/input-stepper-skeleton.d.ts.map +1 -1
  100. package/dist/esm/types/components/input-stepper/input-stepper.component.d.ts +1 -1
  101. package/dist/esm/types/components/input-stepper/input-stepper.component.d.ts.map +1 -1
  102. package/dist/esm/types/components/link-field/link-field.component.d.ts +1 -1
  103. package/dist/esm/types/components/link-field/link-field.component.d.ts.map +1 -1
  104. package/dist/esm/types/components/modal/index.d.ts +2 -2
  105. package/dist/esm/types/components/modal/index.d.ts.map +1 -1
  106. package/dist/esm/types/components/modal/modal-card.component.d.ts +1 -1
  107. package/dist/esm/types/components/modal/modal-card.component.d.ts.map +1 -1
  108. package/dist/esm/types/components/modal/modal.component.d.ts +1 -1
  109. package/dist/esm/types/components/modal/modal.component.d.ts.map +1 -1
  110. package/dist/esm/types/components/money-field/money-field.component.d.ts +1 -1
  111. package/dist/esm/types/components/money-field/money-field.component.d.ts.map +1 -1
  112. package/dist/esm/types/components/phone-number-field/phone-number-field.component.d.ts +1 -1
  113. package/dist/esm/types/components/phone-number-field/phone-number-field.component.d.ts.map +1 -1
  114. package/dist/esm/types/components/pin/pin.component.d.ts +1 -1
  115. package/dist/esm/types/components/pin/pin.component.d.ts.map +1 -1
  116. package/dist/esm/types/components/search-dropdown/search-dropdown.component.d.ts +1 -1
  117. package/dist/esm/types/components/search-dropdown/search-dropdown.component.d.ts.map +1 -1
  118. package/dist/esm/types/components/search-field/search-field.component.d.ts +1 -1
  119. package/dist/esm/types/components/search-field/search-field.component.d.ts.map +1 -1
  120. package/dist/esm/types/components/switch/switch-content.component.d.ts +1 -1
  121. package/dist/esm/types/components/switch/switch-content.component.d.ts.map +1 -1
  122. package/dist/esm/types/components/switch/switch.component.d.ts +1 -1
  123. package/dist/esm/types/components/switch/switch.component.d.ts.map +1 -1
  124. package/dist/esm/types/components/tab/tab.component.d.ts +1 -1
  125. package/dist/esm/types/components/tab/tab.component.d.ts.map +1 -1
  126. package/dist/esm/types/components/text-area/text-area.component.d.ts +1 -1
  127. package/dist/esm/types/components/text-area/text-area.component.d.ts.map +1 -1
  128. package/dist/esm/types/components/text-field/text-field.component.d.ts +1 -1
  129. package/dist/esm/types/components/text-field/text-field.component.d.ts.map +1 -1
  130. package/dist/esm/types/components/typography/typography-limit-one-line.component.d.ts +1 -1
  131. package/dist/esm/types/components/typography/typography-limit-one-line.component.d.ts.map +1 -1
  132. package/dist/esm/types/components/uploader/uploader-item.component.d.ts +1 -1
  133. package/dist/esm/types/components/uploader/uploader-item.component.d.ts.map +1 -1
  134. package/dist/esm/types/components/uploader/uploader.component.d.ts +1 -1
  135. package/dist/esm/types/components/uploader/uploader.component.d.ts.map +1 -1
  136. package/package.json +1 -1
package/dist/cjs/index.js CHANGED
@@ -8,21 +8,21 @@ var LinkIcon = require('@mui/icons-material/Link');
8
8
  var CheckIcon = require('@mui/icons-material/Check');
9
9
  var RemoveIcon = require('@mui/icons-material/Remove');
10
10
  var FiberManualRecordIcon = require('@mui/icons-material/FiberManualRecord');
11
- require('@mui/x-date-pickers/DatePicker');
12
- require('@mui/x-date-pickers/LocalizationProvider');
13
- require('@mui/x-date-pickers/AdapterDayjs');
14
- require('dayjs');
15
- require('@mui/icons-material/Add');
11
+ var DatePicker = require('@mui/x-date-pickers/DatePicker');
12
+ var LocalizationProvider = require('@mui/x-date-pickers/LocalizationProvider');
13
+ var AdapterDayjs = require('@mui/x-date-pickers/AdapterDayjs');
14
+ var dayjs = require('dayjs');
15
+ var AddIcon = require('@mui/icons-material/Add');
16
16
  var MuiTextField = require('@mui/material/TextField');
17
17
  var formik = require('formik');
18
18
  var Slider = require('react-slick');
19
19
  require('slick-carousel/slick/slick.css');
20
20
  require('slick-carousel/slick/slick-theme.css');
21
- require('@mui/icons-material/AttachMoney');
22
- require('@mui/icons-material/Search');
23
- require('framer-motion');
24
- require('@mui/icons-material/CheckCircle');
25
- require('@mui/icons-material/Refresh');
21
+ var AttachMoneyIcon = require('@mui/icons-material/AttachMoney');
22
+ var SearchIcon = require('@mui/icons-material/Search');
23
+ var framerMotion = require('framer-motion');
24
+ var CheckCircleIcon = require('@mui/icons-material/CheckCircle');
25
+ var RefreshIcon = require('@mui/icons-material/Refresh');
26
26
 
27
27
  const AVATAR_SIZES = {
28
28
  xs: 24,
@@ -233,7 +233,7 @@ const FONT_SIZE_ICON = {
233
233
  medium: '19px',
234
234
  small: '12px',
235
235
  };
236
- const FONT_SIZE_LOADING = {
236
+ const FONT_SIZE_LOADING$1 = {
237
237
  large: 40,
238
238
  medium: 22.5,
239
239
  small: 16,
@@ -274,7 +274,7 @@ var style_constant = /*#__PURE__*/Object.freeze({
274
274
  BORDER_RADIUS_ELEMENT_TAG: BORDER_RADIUS_ELEMENT_TAG,
275
275
  BORDER_RADIUS_ELEMENT_WRAPPER: BORDER_RADIUS_ELEMENT_WRAPPER,
276
276
  FONT_SIZE_ICON: FONT_SIZE_ICON,
277
- FONT_SIZE_LOADING: FONT_SIZE_LOADING,
277
+ FONT_SIZE_LOADING: FONT_SIZE_LOADING$1,
278
278
  GAP_ICON_CONTENT_BY_SIZE: GAP_ICON_CONTENT_BY_SIZE,
279
279
  HEIGHT_DEFAULT_TEXT_FIELD_BUTTON: HEIGHT_DEFAULT_TEXT_FIELD_BUTTON,
280
280
  HEIGHT_ELEMENT_OTHER: HEIGHT_ELEMENT_OTHER,
@@ -910,7 +910,7 @@ styles.styled(material.Stack)(() => ({
910
910
  alignItems: 'center',
911
911
  justifyContent: 'center',
912
912
  }));
913
- styles.styled(material.Stack)(() => ({
913
+ const StackRowAlignCenterJustEnd = styles.styled(material.Stack)(() => ({
914
914
  flexDirection: 'row',
915
915
  alignItems: 'center',
916
916
  justifyContent: 'flex-end',
@@ -923,7 +923,7 @@ styles.styled(material.Stack)(() => ({
923
923
  flexDirection: 'row',
924
924
  justifyContent: 'space-between',
925
925
  }));
926
- styles.styled(material.Stack)(() => ({
926
+ const StackRowAlignCenterJustBetween = styles.styled(material.Stack)(() => ({
927
927
  flexDirection: 'row',
928
928
  alignItems: 'center',
929
929
  justifyContent: 'space-between',
@@ -1202,6 +1202,60 @@ const AvatarUserComponent = ({ title, description, descriptionHref, onDescriptio
1202
1202
  }, children: [jsxRuntime.jsx(LinkIcon, { sx: { fontSize: 16, color: descriptionColor } }), description] }))] })] }));
1203
1203
  };
1204
1204
 
1205
+ const SEPARATOR_URLS = {
1206
+ '>': '/images/icon/chevron-right.svg',
1207
+ '/': '/images/icon/slash-separator.svg',
1208
+ };
1209
+ const BreadcrumbsComponent = ({ items, separator = '>', maxItems = 5, idSelect, sx, sxItem, onChange, }) => {
1210
+ // state
1211
+ const [anchorEl, setAnchorEl] = React.useState(null);
1212
+ const showCollapsed = items.length > maxItems;
1213
+ const visibleItems = showCollapsed ? [items[0], ...items.slice(-2)] : items;
1214
+ const collapsedItems = showCollapsed ? items.slice(1, -2) : [];
1215
+ // function
1216
+ const handleMenuOpen = (event) => {
1217
+ setAnchorEl(event.currentTarget);
1218
+ };
1219
+ const handleMenuClose = () => {
1220
+ setAnchorEl(null);
1221
+ };
1222
+ const renderItem = (item) => {
1223
+ const isActive = item.id === idSelect;
1224
+ return (jsxRuntime.jsxs(material.Link, { href: item.href, onClick: (e) => {
1225
+ if (item.onClick) {
1226
+ e.preventDefault();
1227
+ item.onClick();
1228
+ }
1229
+ if (onChange) {
1230
+ onChange(item.id);
1231
+ }
1232
+ }, sx: {
1233
+ display: 'flex',
1234
+ alignItems: 'center',
1235
+ gap: GAP_ICON_CONTENT_BY_SIZE.medium,
1236
+ ...TYPOGRAPHY_STYLES.textSm.semiBold,
1237
+ color: isActive ? '#000000' : '#676E76',
1238
+ cursor: 'pointer',
1239
+ textDecoration: 'none',
1240
+ ...sxItem,
1241
+ }, children: [item.icon && jsxRuntime.jsx(IconElement, { icon: item.icon }), item.label] }, item.id));
1242
+ };
1243
+ const renderSeparator = () => jsxRuntime.jsx(ImageElement, { sx: { width: 14, height: 14 }, url: SEPARATOR_URLS[separator] });
1244
+ return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(material.Breadcrumbs, { "aria-label": "breadcrumb", sx: { ...sx }, children: showCollapsed ? (jsxRuntime.jsxs(StackRowAlignCenter, { sx: { gap: GAP_ICON_CONTENT_BY_SIZE.small }, children: [renderItem(items[0]), renderSeparator(), jsxRuntime.jsx(material.IconButton, { size: "small", onClick: handleMenuOpen, sx: { p: 0, mt: 'auto' }, children: jsxRuntime.jsx(IconElement, { icon: "more_horiz" }) }), renderSeparator(), visibleItems.slice(1).map((item, idx) => (jsxRuntime.jsxs(React.Fragment, { children: [idx > 0 && renderSeparator(), renderItem(item)] }, item.id)))] })) : (items.map((item) => renderItem(item))) }), jsxRuntime.jsx(material.Menu, { anchorEl: anchorEl, open: Boolean(anchorEl), onClose: handleMenuClose, disableScrollLock: true, children: collapsedItems.map((item) => {
1245
+ const isActive = item.id === idSelect;
1246
+ return (jsxRuntime.jsxs(material.MenuItem, { onClick: () => {
1247
+ if (item.onClick) {
1248
+ item.onClick();
1249
+ }
1250
+ handleMenuClose();
1251
+ }, sx: {
1252
+ gap: GAP_ICON_CONTENT_BY_SIZE.medium,
1253
+ color: isActive ? '#0F766E' : '#111827',
1254
+ bgcolor: isActive ? '#E0F2FE' : 'transparent',
1255
+ }, children: [item.icon && jsxRuntime.jsx(IconElement, { icon: item.icon }), item.label] }, item.id));
1256
+ }) })] }));
1257
+ };
1258
+
1205
1259
  /** Shade values mapping */
1206
1260
  const SHADE_VALUES = {
1207
1261
  light: 100,
@@ -1342,6 +1396,17 @@ const ButtonComponent = ({ variant = 'solid', color = 'brand', shade = 'dark', s
1342
1396
  return (jsxRuntime.jsx(material.Button, { sx: { ...buttonSx, ...sx }, disabled: disabled || loading, fullWidth: fullWidth, startIcon: !isIconOnly ? prefixContent : undefined, endIcon: !isIconOnly ? suffixContent : undefined, ...props, children: isIconOnly ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [prefixContent, suffixContent] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [activeDot, children] })) }));
1343
1397
  };
1344
1398
 
1399
+ const ButtonBarComponent = ({ layout, children, gap = 12, style }) => {
1400
+ const containerStyle = {
1401
+ display: 'flex',
1402
+ flexDirection: layout === 'horizontal' ? 'row' : 'column',
1403
+ gap: `${gap}px`,
1404
+ alignItems: layout === 'horizontal' ? 'center' : 'stretch',
1405
+ ...style,
1406
+ };
1407
+ return jsxRuntime.jsx("div", { style: containerStyle, children: children });
1408
+ };
1409
+
1345
1410
  const CHECKBOX_COLORS = {
1346
1411
  default: {
1347
1412
  border: '#D0D5DD',
@@ -1505,6 +1570,358 @@ const CheckboxContentComponent = ({ checked = false, disabled = false, title, co
1505
1570
  }, children: content }))] })] }));
1506
1571
  };
1507
1572
 
1573
+ const CHIP_LABEL_PADDING = {
1574
+ WITH_ICON_LEFT: '4px 8px 4px 4px',
1575
+ WITH_ICON_RIGHT: '4px 4px 4px 8px',
1576
+ NO_ICON: '4px 8px',
1577
+ };
1578
+ const CHIP_SIZE_CONFIG = {
1579
+ small: {
1580
+ height: 24,
1581
+ fontSize: '12px',
1582
+ borderRadius: '12px',
1583
+ iconSize: '16px',
1584
+ },
1585
+ medium: {
1586
+ height: 32,
1587
+ fontSize: '14px',
1588
+ borderRadius: '16px',
1589
+ iconSize: '18px',
1590
+ },
1591
+ large: {
1592
+ height: 40,
1593
+ fontSize: '16px',
1594
+ borderRadius: '20px',
1595
+ iconSize: '22px',
1596
+ },
1597
+ };
1598
+
1599
+ const getLabelPadding = (hasIcon, position) => {
1600
+ if (!hasIcon)
1601
+ return CHIP_LABEL_PADDING.NO_ICON;
1602
+ return position === 'left' ? CHIP_LABEL_PADDING.WITH_ICON_LEFT : CHIP_LABEL_PADDING.WITH_ICON_RIGHT;
1603
+ };
1604
+ const ChipIcon = ({ icon, size, sxIcon }) => (jsxRuntime.jsx(material.Box, { sx: {
1605
+ display: 'inline-flex',
1606
+ alignItems: 'center',
1607
+ justifyContent: 'center',
1608
+ borderRadius: '50%',
1609
+ padding: '2px',
1610
+ '& svg': {
1611
+ width: size,
1612
+ height: size,
1613
+ display: 'block',
1614
+ },
1615
+ ...sxIcon,
1616
+ }, children: icon }));
1617
+ const ChipComponent = ({ label, onAction, icon, disabled = false, clickable = true, sx, sxIcon, iconPosition = 'right', size = 'medium', }) => {
1618
+ const sizeConfig = CHIP_SIZE_CONFIG[size];
1619
+ const hasIcon = Boolean(icon);
1620
+ return (jsxRuntime.jsx(material.Chip, { disabled: disabled, clickable: clickable, onClick: onAction, label: jsxRuntime.jsxs(StackRowAlignCenter, { sx: { gap: '8px' }, children: [hasIcon && iconPosition === 'left' && jsxRuntime.jsx(ChipIcon, { icon: icon, size: sizeConfig.iconSize, sxIcon: sxIcon }), jsxRuntime.jsx(material.Box, { component: "span", children: label }), hasIcon && iconPosition === 'right' && jsxRuntime.jsx(ChipIcon, { icon: icon, size: sizeConfig.iconSize, sxIcon: sxIcon })] }), sx: {
1621
+ height: sizeConfig.height,
1622
+ fontSize: sizeConfig.fontSize,
1623
+ borderRadius: sizeConfig.borderRadius,
1624
+ cursor: clickable ? 'pointer' : 'default',
1625
+ backgroundColor: 'transparent',
1626
+ border: '1px solid #D1D5DB',
1627
+ '& .MuiChip-label': {
1628
+ padding: getLabelPadding(hasIcon, iconPosition),
1629
+ display: 'flex',
1630
+ alignItems: 'center',
1631
+ },
1632
+ '& .MuiChip-label svg': {
1633
+ flexShrink: 0,
1634
+ color: '#4B5563',
1635
+ },
1636
+ '&.Mui-disabled': {
1637
+ opacity: 0.5,
1638
+ color: '#9E9E9E',
1639
+ },
1640
+ ...sx,
1641
+ } }));
1642
+ };
1643
+
1644
+ const DateFieldComponent = ({ label = 'Label', placeholder = 'DD/MM/YYYY', value, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, helperText = '', onChange, locale = 'vi', format = 'DD/MM/YYYY', sx, disablePastDates = false, ...props }) => {
1645
+ // Convert string to Dayjs if needed
1646
+ const dayjsValue = value && typeof value === 'string' ? dayjs(value, format) : value instanceof dayjs ? value : null;
1647
+ const handleDateChange = (date) => {
1648
+ onChange?.(date);
1649
+ };
1650
+ // Disable past dates function
1651
+ const shouldDisableDate = (date) => {
1652
+ if (!disablePastDates)
1653
+ return false;
1654
+ return date.isBefore(dayjs(), 'day');
1655
+ };
1656
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
1657
+ display: 'block',
1658
+ ...TYPOGRAPHY.textFieldLabel,
1659
+ color: COLOR_GRAY[800],
1660
+ marginBottom: '4px',
1661
+ }, children: label })), jsxRuntime.jsx(LocalizationProvider.LocalizationProvider, { dateAdapter: AdapterDayjs.AdapterDayjs, adapterLocale: locale, children: jsxRuntime.jsx(DatePicker.DatePicker, { value: dayjsValue, onChange: handleDateChange, disabled: disabled, format: format, shouldDisableDate: shouldDisableDate, slotProps: {
1662
+ textField: {
1663
+ placeholder,
1664
+ error: error || false,
1665
+ helperText: error ? errorMessage : helperText,
1666
+ size: 'small',
1667
+ fullWidth: true,
1668
+ disabled: disabled,
1669
+ },
1670
+ openPickerButton: {
1671
+ size: 'small',
1672
+ },
1673
+ }, slots: {
1674
+ openPickerIcon: (props) => jsxRuntime.jsx(IconElement, { icon: "calendar_today", ...props }),
1675
+ }, sx: {
1676
+ width: '100%',
1677
+ '& .MuiPickersInputBase-root': {
1678
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
1679
+ '& fieldset': { borderColor: COLOR_NEUTRAL[300] },
1680
+ '&:hover fieldset': { borderColor: COLOR_NEUTRAL[400] },
1681
+ '&.Mui-focused fieldset': { borderColor: COLOR_NEUTRAL[300], borderWidth: '2px' },
1682
+ '&.Mui-focused': {
1683
+ boxShadow: '0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px #FEE4E2',
1684
+ },
1685
+ '&.Mui-disabled': {
1686
+ backgroundColor: COLOR_NEUTRAL[100],
1687
+ '& fieldset': { borderColor: COLOR_NEUTRAL[200] },
1688
+ '& input': { color: COLOR_NEUTRAL[400], WebkitTextFillColor: COLOR_NEUTRAL[400] },
1689
+ },
1690
+ '&.Mui-error fieldset': { borderColor: COLOR_ERROR[500] },
1691
+ '&.Mui-error.Mui-focused fieldset': { borderColor: COLOR_ERROR[500], borderWidth: '2px' },
1692
+ '&.Mui-error.Mui-focused': {
1693
+ boxShadow: `0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px rgba(255, 66, 79, 0.15)`,
1694
+ },
1695
+ ...(success && {
1696
+ '&.Mui-focused': {
1697
+ boxShadow: `0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px ${COLOR_SUCCESS[100]}`,
1698
+ },
1699
+ }),
1700
+ },
1701
+ '& .MuiInputBase-input': {
1702
+ ...TYPOGRAPHY.text14Regular,
1703
+ padding: '12px 8px',
1704
+ color: COLOR_GRAY[900],
1705
+ '&::placeholder': { color: COLOR_NEUTRAL[400], opacity: 0.7 },
1706
+ },
1707
+ }, ...props }) }), success && !error && successMessage && (jsxRuntime.jsx(material.Typography, { sx: {
1708
+ ...TYPOGRAPHY.textFieldHelper,
1709
+ color: COLOR_SUCCESS[500],
1710
+ marginTop: '4px',
1711
+ }, children: successMessage }))] }));
1712
+ };
1713
+
1714
+ const DateRangePickerComponent = ({ label = 'Date Range', fromDate, toDate, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, helperText = '', onChange, locale = 'vi', format = 'DD/MM/YYYY', minDate, maxDate, sx, disablePastDates = false, ...props }) => {
1715
+ // Convert string to Dayjs if needed
1716
+ const dayjsFromDate = fromDate && typeof fromDate === 'string' ? dayjs(fromDate, format) : fromDate instanceof dayjs ? fromDate : null;
1717
+ const dayjsToDate = toDate && typeof toDate === 'string' ? dayjs(toDate, format) : toDate instanceof dayjs ? toDate : null;
1718
+ // State for picker
1719
+ const [pickerOpen, setPickerOpen] = React.useState(false);
1720
+ const [selectingPhase, setSelectingPhase] = React.useState('from');
1721
+ const inputRef = React.useRef(null);
1722
+ // Disable past dates function
1723
+ const shouldDisableDate = (date) => {
1724
+ if (!disablePastDates)
1725
+ return false;
1726
+ return date.isBefore(dayjs(), 'day');
1727
+ };
1728
+ const handleInputClick = () => {
1729
+ setPickerOpen(true);
1730
+ // Only reset to 'from' if both dates are empty (fresh start)
1731
+ if (!dayjsFromDate && !dayjsToDate) {
1732
+ setSelectingPhase('from');
1733
+ }
1734
+ };
1735
+ const handleDateChange = (date) => {
1736
+ if (selectingPhase === 'from') {
1737
+ onChange?.([date, dayjsToDate]);
1738
+ if (date) {
1739
+ // Auto switch to toDate selection
1740
+ setSelectingPhase('to');
1741
+ }
1742
+ }
1743
+ else {
1744
+ onChange?.([dayjsFromDate, date]);
1745
+ // Keep picker open for user to potentially change toDate
1746
+ }
1747
+ };
1748
+ return (jsxRuntime.jsx(LocalizationProvider.LocalizationProvider, { dateAdapter: AdapterDayjs.AdapterDayjs, adapterLocale: locale, children: jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
1749
+ display: 'block',
1750
+ ...TYPOGRAPHY.textFieldLabel,
1751
+ color: COLOR_GRAY[800],
1752
+ marginBottom: '4px',
1753
+ }, children: label })), jsxRuntime.jsxs(material.Box, { ref: inputRef, onClick: !disabled ? handleInputClick : undefined, sx: {
1754
+ display: 'flex',
1755
+ alignItems: 'center',
1756
+ gap: '12px',
1757
+ padding: '12px 8px',
1758
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
1759
+ border: `1px solid ${error ? COLOR_ERROR[500] : COLOR_NEUTRAL[300]}`,
1760
+ backgroundColor: disabled ? COLOR_NEUTRAL[100] : 'white',
1761
+ cursor: disabled ? 'default' : 'pointer',
1762
+ transition: 'all 0.2s ease',
1763
+ ...(disabled
1764
+ ? {}
1765
+ : {
1766
+ '&:hover': {
1767
+ borderColor: error ? COLOR_ERROR[500] : COLOR_NEUTRAL[400],
1768
+ },
1769
+ }),
1770
+ }, children: [jsxRuntime.jsxs(material.Typography, { sx: {
1771
+ flex: 1,
1772
+ ...TYPOGRAPHY.text14Regular,
1773
+ color: dayjsFromDate || dayjsToDate ? COLOR_GRAY[900] : COLOR_NEUTRAL[400],
1774
+ }, children: [dayjsFromDate ? dayjsFromDate.format(format) : format, " \u2192", ' ', dayjsToDate ? dayjsToDate.format(format) : format] }), jsxRuntime.jsx(material.Box, { sx: {
1775
+ display: 'flex',
1776
+ alignItems: 'center',
1777
+ justifyContent: 'center',
1778
+ width: '24px',
1779
+ height: '24px',
1780
+ color: COLOR_NEUTRAL[400],
1781
+ }, children: jsxRuntime.jsx(IconElement, { icon: "calendar_today" }) })] }), jsxRuntime.jsx(DatePicker.DatePicker, { open: pickerOpen, onOpen: () => setPickerOpen(true), onClose: () => setPickerOpen(false), value: selectingPhase === 'from' ? dayjsFromDate : dayjsToDate, onChange: handleDateChange, disabled: disabled, format: format, minDate: selectingPhase === 'from' ? minDate : dayjsFromDate || minDate, maxDate: selectingPhase === 'to' ? maxDate : dayjsToDate || maxDate, shouldDisableDate: shouldDisableDate, slotProps: {
1782
+ textField: {
1783
+ hidden: true,
1784
+ size: 'small',
1785
+ sx: {
1786
+ display: 'none',
1787
+ },
1788
+ },
1789
+ popper: {
1790
+ anchorEl: inputRef.current,
1791
+ placement: 'bottom-start',
1792
+ },
1793
+ } }), helperText && !error && !success && (jsxRuntime.jsx(material.Typography, { sx: {
1794
+ ...TYPOGRAPHY.textFieldHelper,
1795
+ color: COLOR_NEUTRAL[400],
1796
+ marginTop: '4px',
1797
+ }, children: helperText })), error && errorMessage && (jsxRuntime.jsx(material.Typography, { sx: {
1798
+ ...TYPOGRAPHY.textFieldHelper,
1799
+ color: COLOR_ERROR[500],
1800
+ marginTop: '4px',
1801
+ }, children: errorMessage })), success && !error && successMessage && (jsxRuntime.jsx(material.Typography, { sx: {
1802
+ ...TYPOGRAPHY.textFieldHelper,
1803
+ color: COLOR_SUCCESS[500],
1804
+ marginTop: '4px',
1805
+ }, children: successMessage }))] }) }));
1806
+ };
1807
+
1808
+ const DropdownFieldComponent = ({ label = '', placeholder = 'Select option', value = null, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, onChange, helperText = '', options = [], checkIconColor = COLOR_ACCENT[900], sx, }) => {
1809
+ const borderRadiusValue = borderRadius === 'max' ? '100px' : `${borderRadius}px`;
1810
+ const selectedOption = React.useMemo(() => options.find((opt) => opt.value === value), [options, value]);
1811
+ const getHelperText = React.useCallback(() => {
1812
+ if (error && errorMessage)
1813
+ return errorMessage;
1814
+ if (success && successMessage)
1815
+ return successMessage;
1816
+ if (helperText)
1817
+ return helperText;
1818
+ return '';
1819
+ }, [error, errorMessage, success, successMessage, helperText]);
1820
+ const getHelperTextColor = React.useCallback(() => {
1821
+ if (error)
1822
+ return COLOR_ERROR[500];
1823
+ if (success)
1824
+ return COLOR_SUCCESS[500];
1825
+ return COLOR_NEUTRAL[400];
1826
+ }, [error, success]);
1827
+ const getBorderColor = React.useCallback(() => {
1828
+ if (error)
1829
+ return COLOR_ERROR[500];
1830
+ if (success)
1831
+ return COLOR_SUCCESS[500];
1832
+ return COLOR_NEUTRAL[300];
1833
+ }, [error, success]);
1834
+ const selectSx = React.useMemo(() => ({
1835
+ '& .MuiOutlinedInput-root': {
1836
+ borderRadius: borderRadiusValue,
1837
+ backgroundColor: disabled ? COLOR_NEUTRAL[100] : 'white',
1838
+ transition: 'all 0.2s ease',
1839
+ '& fieldset': {
1840
+ borderColor: getBorderColor(),
1841
+ },
1842
+ '&:hover fieldset': {
1843
+ borderColor: disabled ? getBorderColor() : error ? COLOR_ERROR[500] : COLOR_NEUTRAL[400],
1844
+ },
1845
+ '&.Mui-focused fieldset': {
1846
+ borderColor: error ? COLOR_ERROR[500] : COLOR_NEUTRAL[400],
1847
+ borderWidth: '1.5px',
1848
+ },
1849
+ },
1850
+ '& .MuiOutlinedInput-input': {
1851
+ padding: '12px 14px',
1852
+ color: COLOR_GRAY[900],
1853
+ '&::placeholder': {
1854
+ color: COLOR_NEUTRAL[400],
1855
+ opacity: 1,
1856
+ },
1857
+ },
1858
+ }), [borderRadiusValue, disabled, error, getBorderColor]);
1859
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
1860
+ display: 'block',
1861
+ ...TYPOGRAPHY.textFieldLabel,
1862
+ color: COLOR_GRAY[800],
1863
+ marginBottom: '4px',
1864
+ }, children: label })), jsxRuntime.jsx(material.Select, { fullWidth: true, value: value || '', onChange: (e) => {
1865
+ const selectedValue = e.target.value;
1866
+ const matchedOption = options.find((opt) => String(opt.value) === String(selectedValue));
1867
+ if (matchedOption) {
1868
+ onChange?.(matchedOption.value);
1869
+ }
1870
+ }, disabled: disabled, displayEmpty: true, MenuProps: {
1871
+ disableScrollLock: true,
1872
+ }, renderValue: () => {
1873
+ if (!value) {
1874
+ return (jsxRuntime.jsx(material.Box, { sx: { color: COLOR_NEUTRAL[400], display: 'flex', alignItems: 'center', gap: '8px' }, children: placeholder }));
1875
+ }
1876
+ return (jsxRuntime.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [selectedOption?.statusIndicator && (jsxRuntime.jsx(material.Box, { sx: {
1877
+ width: '8px',
1878
+ height: '8px',
1879
+ borderRadius: '50%',
1880
+ backgroundColor: '#4CAF50',
1881
+ } })), selectedOption?.avatar && (jsxRuntime.jsx(material.Avatar, { src: selectedOption.avatar, sx: {
1882
+ width: '24px',
1883
+ height: '24px',
1884
+ fontSize: '12px',
1885
+ } })), selectedOption?.icon && jsxRuntime.jsx(IconElement, { icon: selectedOption.icon }), jsxRuntime.jsx(material.Typography, { sx: { color: COLOR_GRAY[900], ...TYPOGRAPHY.text14Regular }, children: selectedOption?.label })] }));
1886
+ }, sx: selectSx, children: options.map((option) => (jsxRuntime.jsx(material.MenuItem, { value: option.value, children: jsxRuntime.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: '8px', width: '100%' }, children: [option.statusIndicator && (jsxRuntime.jsx(material.Box, { sx: {
1887
+ width: '8px',
1888
+ height: '8px',
1889
+ borderRadius: '50%',
1890
+ backgroundColor: '#4CAF50',
1891
+ } })), option.avatar && (jsxRuntime.jsx(material.Avatar, { src: option.avatar, sx: {
1892
+ width: '24px',
1893
+ height: '24px',
1894
+ fontSize: '12px',
1895
+ } })), option.icon && jsxRuntime.jsx(IconElement, { icon: option.icon }), jsxRuntime.jsx(material.Typography, { sx: { color: COLOR_GRAY[900], ...TYPOGRAPHY.text14Regular }, children: option.label }), value === option.value && (jsxRuntime.jsx(material.Box, { sx: { marginLeft: 'auto', display: 'flex', alignItems: 'center' }, children: jsxRuntime.jsx(IconElement, { icon: "check", sx: { color: checkIconColor } }) }))] }) }, option.value))) }), getHelperText() && (jsxRuntime.jsx(material.Box, { sx: {
1896
+ color: getHelperTextColor(),
1897
+ marginTop: '4px',
1898
+ ...TYPOGRAPHY.textFieldHelper,
1899
+ }, children: getHelperText() }))] }));
1900
+ };
1901
+
1902
+ const BACKGROUND_COLOR_GRID = '#FFFFFF';
1903
+ const COLOR_CONTENT_GRID = '#27272A';
1904
+ const BORDER_RADIUS_GRID_CONTAINER = 8;
1905
+ const BORDER_RADIUS_GRID = 4;
1906
+ const GridComponent = ({ sx = {}, sxContainer = {}, content = 'Grids', children, }) => {
1907
+ return (jsxRuntime.jsxs(material.Stack, { sx: {
1908
+ bgcolor: BACKGROUND_COLOR_GRID,
1909
+ p: BORDER_RADIUS_GRID_CONTAINER,
1910
+ borderRadius: BORDER_RADIUS_GRID_CONTAINER,
1911
+ gap: BORDER_RADIUS_GRID,
1912
+ ...sx,
1913
+ }, children: [content && (jsxRuntime.jsx(material.Typography, { sx: {
1914
+ color: COLOR_CONTENT_GRID,
1915
+ ...TYPOGRAPHY_STYLES.lg.bold,
1916
+ }, children: content })), jsxRuntime.jsx(material.Container, { maxWidth: false, sx: {
1917
+ bgcolor: BACKGROUND_COLOR_GRID,
1918
+ borderRadius: BORDER_RADIUS_GRID,
1919
+ minHeight: 400,
1920
+ boxShadow: '0 0 8px -4px rgba(16, 24, 40, 0.3)',
1921
+ ...sxContainer,
1922
+ }, children: children })] }));
1923
+ };
1924
+
1508
1925
  var BorderRadius;
1509
1926
  (function (BorderRadius) {
1510
1927
  BorderRadius["SQUARE"] = "4px";
@@ -1525,6 +1942,159 @@ var ButtonSize;
1525
1942
  ButtonSize[ButtonSize["SMALL"] = 32] = "SMALL";
1526
1943
  ButtonSize[ButtonSize["MEDIUM"] = 40] = "MEDIUM";
1527
1944
  })(ButtonSize || (ButtonSize = {}));
1945
+ const Colors = {
1946
+ BORDER_COLOR_BUTTON: '#07554B',
1947
+ BORDER_COLOR_DISABLE: '#0000000D',
1948
+ HOVER_BG_COLOR: 'rgba(7, 85, 75, 0.04)',
1949
+ BACKGROUND_COLOR: '#FFFFFF',
1950
+ TEXT_COLOR_READONLY: '#27272A',
1951
+ };
1952
+ const FONT_SIZE_LOADING = {
1953
+ large: 40,
1954
+ };
1955
+ const BORDER_TEXT_FIELD_LOADING = 20;
1956
+
1957
+ const InputStepperSkeleton = ({ orientation, buttonShape }) => {
1958
+ return (jsxRuntime.jsxs(material.Box, { display: "inline-flex", flexDirection: orientation === Orientation.HORIZONTAL ? 'row' : 'column', alignItems: "center", gap: 1, children: [jsxRuntime.jsx(material.Skeleton, { variant: buttonShape === ShapeType.CIRCLE ? 'circular' : 'rectangular', width: FONT_SIZE_LOADING.large, height: FONT_SIZE_LOADING.large, sx: {
1959
+ borderRadius: buttonShape === ShapeType.CIRCLE ? BorderRadius.CIRCLE : BorderRadius.SQUARE,
1960
+ maxHeight: FONT_SIZE_LOADING.large,
1961
+ } }), jsxRuntime.jsx(material.Skeleton, { width: FONT_SIZE_LOADING.large, sx: {
1962
+ borderRadius: `${BORDER_TEXT_FIELD_LOADING}px`,
1963
+ } }), jsxRuntime.jsx(material.Skeleton, { variant: buttonShape === ShapeType.CIRCLE ? 'circular' : 'rectangular', width: FONT_SIZE_LOADING.large, height: FONT_SIZE_LOADING.large, sx: {
1964
+ borderRadius: buttonShape === ShapeType.CIRCLE ? BorderRadius.CIRCLE : BorderRadius.SQUARE,
1965
+ maxHeight: FONT_SIZE_LOADING.large,
1966
+ } })] }));
1967
+ };
1968
+
1969
+ const InputStepperComponent = ({ value: controlledValue, onChange, min, max, step = 1, disabled = false, readOnly = false, orientation = Orientation.HORIZONTAL, loading = false, sx = {}, sxTextField = {}, // style cho input chứa value
1970
+ sxButton = {}, // style cho 2 button
1971
+ buttonShape = ShapeType.SQUARE, buttonColor, textFieldShape = ShapeType.SQUARE, decrementIcon = jsxRuntime.jsx(RemoveIcon, {}), incrementIcon = jsxRuntime.jsx(AddIcon, {}), }) => {
1972
+ const [internalValue, setInternalValue] = React.useState(controlledValue ?? min ?? 0);
1973
+ const value = controlledValue !== undefined ? controlledValue : internalValue;
1974
+ const updateValue = (newValue) => {
1975
+ let finalValue = newValue;
1976
+ if (min !== undefined && newValue < min)
1977
+ finalValue = min;
1978
+ if (max !== undefined && newValue > max)
1979
+ finalValue = max;
1980
+ if (controlledValue === undefined) {
1981
+ setInternalValue(finalValue);
1982
+ }
1983
+ onChange?.(finalValue);
1984
+ };
1985
+ const handleIncrement = () => {
1986
+ updateValue(Number(value) + step);
1987
+ };
1988
+ const handleDecrement = () => {
1989
+ updateValue(Number(value) - step);
1990
+ };
1991
+ const handleInputChange = (event) => {
1992
+ if (!readOnly) {
1993
+ const newValue = event.target.value === '' ? min || 0 : Number(event.target.value);
1994
+ if (!isNaN(newValue)) {
1995
+ updateValue(newValue);
1996
+ }
1997
+ }
1998
+ };
1999
+ const isDecrementDisabled = disabled || (min !== undefined && Number(value) <= min);
2000
+ const isIncrementDisabled = disabled || (max !== undefined && Number(value) >= max);
2001
+ const buttonSize = ButtonSize.MEDIUM;
2002
+ if (loading) {
2003
+ return jsxRuntime.jsx(InputStepperSkeleton, { orientation: orientation, buttonShape: buttonShape });
2004
+ }
2005
+ return (jsxRuntime.jsxs(material.Box, { display: "inline-flex", flexDirection: orientation === 'horizontal' ? 'row' : 'column', alignItems: "center", gap: PADDING_GAP_ITEM, sx: {
2006
+ opacity: disabled ? 0.5 : 1,
2007
+ pointerEvents: disabled ? 'none' : 'auto',
2008
+ ...sx,
2009
+ }, children: [jsxRuntime.jsx(material.IconButton, { onClick: handleDecrement, disabled: isDecrementDisabled, sx: {
2010
+ borderRadius: buttonShape === 'circle' ? BorderRadius.CIRCLE : BorderRadius.SQUARE,
2011
+ width: buttonSize,
2012
+ height: buttonSize,
2013
+ padding: PADDING_GAP_ITEM,
2014
+ border: isDecrementDisabled
2015
+ ? `1px solid ${Colors.BORDER_COLOR_DISABLE}`
2016
+ : `1px solid ${Colors.BORDER_COLOR_BUTTON}`,
2017
+ backgroundColor: Colors.BACKGROUND_COLOR,
2018
+ color: buttonColor || Colors.BORDER_COLOR_BUTTON,
2019
+ '&:hover': {
2020
+ backgroundColor: Colors.HOVER_BG_COLOR,
2021
+ },
2022
+ ...(isDecrementDisabled ? {} : sxButton),
2023
+ }, children: decrementIcon }), jsxRuntime.jsx(material.TextField, { value: value, onChange: handleInputChange, disabled: disabled, inputProps: {
2024
+ min,
2025
+ max,
2026
+ step,
2027
+ readOnly,
2028
+ }, type: "number", sx: {
2029
+ minWidth: buttonSize,
2030
+ width: sxTextField?.width || buttonSize,
2031
+ minHeight: buttonSize,
2032
+ height: sxTextField?.height || buttonSize,
2033
+ overflow: 'hidden',
2034
+ borderRadius: textFieldShape === 'circle' ? BorderRadius.CIRCLE : BorderRadius.SQUARE,
2035
+ color: readOnly ? Colors.TEXT_COLOR_READONLY : '',
2036
+ backgroundColor: readOnly ? 'transparent !important' : sxTextField?.backgroundColor,
2037
+ '& .MuiOutlinedInput-root': {
2038
+ width: '100%',
2039
+ height: '100%',
2040
+ borderRadius: 'inherit',
2041
+ '& fieldset': {
2042
+ borderColor: readOnly || disabled ? 'transparent' : sxTextField?.borderColor || Colors.BORDER_COLOR_BUTTON,
2043
+ borderWidth: readOnly || disabled ? 0 : 1,
2044
+ borderRadius: textFieldShape === 'circle' ? BorderRadius.CIRCLE : BorderRadius.SQUARE,
2045
+ },
2046
+ '&:hover fieldset': readOnly || disabled
2047
+ ? {}
2048
+ : {
2049
+ borderColor: sxTextField?.borderColorHover || Colors.BORDER_COLOR_BUTTON,
2050
+ },
2051
+ '&.Mui-focused fieldset': readOnly
2052
+ ? {
2053
+ borderColor: 'transparent',
2054
+ borderWidth: 0,
2055
+ }
2056
+ : {
2057
+ borderColor: sxTextField?.borderColorFocused || Colors.BORDER_COLOR_BUTTON,
2058
+ borderWidth: 1,
2059
+ },
2060
+ '&.Mui-disabled fieldset': {
2061
+ borderColor: Colors.BORDER_COLOR_DISABLE,
2062
+ backgroundColor: readOnly ? 'transparent' : Colors.BORDER_COLOR_DISABLE,
2063
+ },
2064
+ },
2065
+ '& input[type=number]::-webkit-outer-spin-button, & input[type=number]::-webkit-inner-spin-button': {
2066
+ WebkitAppearance: 'none',
2067
+ margin: 0,
2068
+ },
2069
+ '& input[type=number]': {
2070
+ MozAppearance: 'textfield',
2071
+ },
2072
+ '& .MuiInputBase-input': {
2073
+ textAlign: sxTextField?.textAlign || 'center',
2074
+ padding: sxTextField?.padding || '4px 8px',
2075
+ fontSize: readOnly ? '16px' : sxTextField?.fontSize || '1rem',
2076
+ cursor: readOnly ? 'not-allowed' : 'text',
2077
+ borderRadius: 'inherit',
2078
+ backgroundColor: readOnly ? 'transparent' : sxTextField?.backgroundColor || 'transparent',
2079
+ color: readOnly ? Colors.TEXT_COLOR_READONLY : sxTextField?.color || 'inherit',
2080
+ fontWeight: sxTextField?.fontWeight || (readOnly ? 700 : 'normal'),
2081
+ },
2082
+ } }), jsxRuntime.jsx(material.IconButton, { onClick: handleIncrement, disabled: isIncrementDisabled, sx: {
2083
+ borderRadius: buttonShape === 'circle' ? BorderRadius.CIRCLE : BorderRadius.SQUARE,
2084
+ width: buttonSize,
2085
+ height: buttonSize,
2086
+ padding: PADDING_GAP_ITEM,
2087
+ border: isIncrementDisabled
2088
+ ? `1px solid ${Colors.BORDER_COLOR_DISABLE}`
2089
+ : `1px solid ${Colors.BORDER_COLOR_BUTTON}`,
2090
+ backgroundColor: Colors.BACKGROUND_COLOR,
2091
+ color: buttonColor || Colors.BORDER_COLOR_BUTTON,
2092
+ '&:hover': {
2093
+ backgroundColor: Colors.HOVER_BG_COLOR,
2094
+ },
2095
+ ...(isIncrementDisabled ? {} : sxButton),
2096
+ }, children: incrementIcon })] }));
2097
+ };
1528
2098
 
1529
2099
  const LinkInternalElement = ({ content, onClick, sx = {} }) => {
1530
2100
  return (jsxRuntime.jsx(material.Typography, { onClick: onClick, sx: {
@@ -1547,7 +2117,7 @@ const LinkElement = ({ onClick, sx = {}, target = '_self', ...rest }) => {
1547
2117
  }, ...rest }));
1548
2118
  };
1549
2119
 
1550
- styles.styled(MuiTextField)(({ theme }) => {
2120
+ const StyledTextField$3 = styles.styled(MuiTextField)(({ theme }) => {
1551
2121
  return {
1552
2122
  '& .MuiOutlinedInput-root': {
1553
2123
  '& fieldset': { borderColor: COLOR_NEUTRAL[300] },
@@ -1589,6 +2159,57 @@ styles.styled(MuiTextField)(({ theme }) => {
1589
2159
  },
1590
2160
  };
1591
2161
  });
2162
+ const LinkFieldComponent = ({ label = 'Website', placeholder = 'www.untitledui.com', value, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, helperText = 'This is a hint text to help user.', onChange, protocol = 'http://', iconAfter, sx, ...props }) => {
2163
+ const [validationError, setValidationError] = React.useState(false);
2164
+ const isValidLink = (url) => {
2165
+ if (!url)
2166
+ return true; // Empty is valid (optional field)
2167
+ try {
2168
+ const urlToTest = url.includes('://') ? url : `${protocol}${url}`;
2169
+ new URL(urlToTest);
2170
+ // Kiểm tra domain phải có dấu chấm (ít nhất là có TLD)
2171
+ const hostname = new URL(urlToTest).hostname;
2172
+ if (!hostname || !hostname.includes('.')) {
2173
+ return false;
2174
+ }
2175
+ return true;
2176
+ }
2177
+ catch {
2178
+ return false;
2179
+ }
2180
+ };
2181
+ const handleBlur = (event) => {
2182
+ const inputValue = event.target.value;
2183
+ if (inputValue && !isValidLink(inputValue)) {
2184
+ setValidationError(true);
2185
+ }
2186
+ else {
2187
+ setValidationError(false);
2188
+ }
2189
+ };
2190
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
2191
+ display: 'block',
2192
+ ...TYPOGRAPHY.textFieldLabel,
2193
+ color: COLOR_GRAY[800],
2194
+ marginBottom: '4px',
2195
+ }, children: label })), jsxRuntime.jsx(StyledTextField$3, { placeholder: placeholder, value: value, disabled: disabled, error: error || validationError, helperText: error || validationError ? (error ? errorMessage : 'đây không phải link') : '', size: "small", fullWidth: true, onChange: onChange, onBlur: handleBlur, InputProps: {
2196
+ startAdornment: (jsxRuntime.jsx(material.InputAdornment, { position: "start", children: jsxRuntime.jsx(material.Typography, { sx: { color: COLOR_NEUTRAL[300], ...TYPOGRAPHY.text14Regular }, children: protocol }) })),
2197
+ endAdornment: (success || error || validationError) && (jsxRuntime.jsx(material.InputAdornment, { position: "end", children: iconAfter ? (iconAfter) : (jsxRuntime.jsx(IconElement, { icon: error || validationError ? 'info' : 'check_circle', sx: { color: error || validationError ? COLOR_ERROR[500] : COLOR_SUCCESS[500] } })) })),
2198
+ }, sx: {
2199
+ '& .MuiOutlinedInput-root': {
2200
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
2201
+ ...(success && {
2202
+ '&.Mui-focused': {
2203
+ boxShadow: `0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px ${COLOR_SUCCESS[100]}`,
2204
+ },
2205
+ }),
2206
+ },
2207
+ } }), success && !error && successMessage && (jsxRuntime.jsx(material.Typography, { sx: {
2208
+ ...TYPOGRAPHY.textFieldHelper,
2209
+ color: COLOR_SUCCESS[500],
2210
+ marginTop: '4px',
2211
+ }, children: successMessage }))] }));
2212
+ };
1592
2213
 
1593
2214
  const MODAL_ICON_COLORS = {
1594
2215
  check_circle: '#10B981',
@@ -1698,7 +2319,15 @@ const ModalCardComponent = ({ open, isForm = false, onClose, items, nodeContent,
1698
2319
  }, children: jsxRuntime.jsxs(StackRowAlignCenter, { sx: { width: '100%' }, children: [nodeBottomLeft && jsxRuntime.jsx(material.Box, { sx: { width: '100%' }, children: nodeBottomLeft }), (buttonLeft || buttonCenter || buttonRight) && (jsxRuntime.jsxs(StackRow, { sx: { width: '100%', gap: PADDING_GAP_LAYOUT }, children: [buttonLeft && (jsxRuntime.jsx(material.Box, { sx: { flex: 1 }, children: jsxRuntime.jsx(ButtonComponent, { ...buttonLeft, fullWidth: true }) })), buttonCenter && (jsxRuntime.jsx(material.Box, { sx: { flex: 1 }, children: jsxRuntime.jsx(ButtonComponent, { ...buttonCenter, fullWidth: true }) })), buttonRight && (jsxRuntime.jsx(material.Box, { sx: { flex: 1 }, children: jsxRuntime.jsx(ButtonComponent, { ...buttonRight, fullWidth: true }) }))] }))] }) }))] }) }));
1699
2320
  };
1700
2321
 
1701
- styles.styled(MuiTextField)(({ theme }) => {
2322
+ const CURRENCIES = ['USD', 'EUR', 'GBP', 'JPY', 'AUD', 'CAD', 'CHF', 'CNY', 'VND', 'INR'];
2323
+ // Format number with thousand separators
2324
+ const formatMoneyDisplay = (value) => {
2325
+ if (!value)
2326
+ return '';
2327
+ const numericOnly = value.replace(/\D/g, '');
2328
+ return numericOnly.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
2329
+ };
2330
+ const StyledTextField$2 = styles.styled(MuiTextField)(({ theme }) => {
1702
2331
  return {
1703
2332
  '& .MuiOutlinedInput-root': {
1704
2333
  '& fieldset': { borderColor: COLOR_NEUTRAL[300] },
@@ -1740,8 +2369,64 @@ styles.styled(MuiTextField)(({ theme }) => {
1740
2369
  },
1741
2370
  };
1742
2371
  });
2372
+ const MoneyFieldComponent = ({ label = 'Sale amount', placeholder = '1,000.00', value, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, helperText = 'This is a hint text to help user.', onChange, currency = 'USD', onCurrencyChange, iconBefore, optionCurrencies = CURRENCIES, sx, ...props }) => {
2373
+ const [selectedCurrency, setSelectedCurrency] = React.useState(currency);
2374
+ const handleCurrencyChange = (e) => {
2375
+ const newCurrency = e.target.value;
2376
+ setSelectedCurrency(newCurrency);
2377
+ onCurrencyChange?.(newCurrency);
2378
+ };
2379
+ const handleMoneyChange = (e) => {
2380
+ const rawValue = e.target.value.replace(/,/g, '');
2381
+ onChange?.({ ...e, target: { ...e.target, value: rawValue } });
2382
+ };
2383
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
2384
+ display: 'block',
2385
+ ...TYPOGRAPHY.textFieldLabel,
2386
+ color: COLOR_GRAY[800],
2387
+ marginBottom: '4px',
2388
+ }, children: label })), jsxRuntime.jsx(StyledTextField$2, { placeholder: placeholder, value: formatMoneyDisplay(value), disabled: disabled, error: error, helperText: error ? errorMessage : helperText, size: "small", fullWidth: true, onChange: handleMoneyChange, InputProps: {
2389
+ startAdornment: (jsxRuntime.jsx(material.InputAdornment, { position: "start", children: iconBefore ? iconBefore : jsxRuntime.jsx(AttachMoneyIcon, { sx: { fontSize: '18px', color: COLOR_GRAY[400], mr: 0.5 } }) })),
2390
+ endAdornment: (jsxRuntime.jsx(material.InputAdornment, { position: "end", children: jsxRuntime.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [(success || error) && (jsxRuntime.jsx(IconElement, { icon: error ? 'info' : 'check_circle', sx: { color: error ? COLOR_ERROR[500] : COLOR_SUCCESS[500] } })), jsxRuntime.jsx(material.Select, { value: selectedCurrency, onChange: handleCurrencyChange, disabled: disabled, variant: "standard", sx: {
2391
+ border: 'none',
2392
+ outline: 'none',
2393
+ '& .MuiSelect-standard': { border: 'none' },
2394
+ '&.MuiInput-underline:before': { borderBottom: 'none' },
2395
+ '&.MuiInput-underline:hover:before': { borderBottom: 'none' },
2396
+ '&.MuiInput-underline:after': { borderBottom: 'none' },
2397
+ minWidth: '70px',
2398
+ fontSize: '14px',
2399
+ color: COLOR_GRAY[500],
2400
+ }, children: optionCurrencies.map((curr) => (jsxRuntime.jsx(material.MenuItem, { value: curr, children: curr }, curr))) })] }) })),
2401
+ }, sx: {
2402
+ '& .MuiOutlinedInput-root': {
2403
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
2404
+ ...(success && {
2405
+ '&.Mui-focused': {
2406
+ boxShadow: `0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px ${COLOR_SUCCESS[100]}`,
2407
+ },
2408
+ }),
2409
+ },
2410
+ } }), success && !error && successMessage && (jsxRuntime.jsx(material.Typography, { sx: {
2411
+ ...TYPOGRAPHY.textFieldHelper,
2412
+ color: COLOR_SUCCESS[600],
2413
+ marginTop: '4px',
2414
+ }, children: successMessage }))] }));
2415
+ };
1743
2416
 
1744
- styles.styled(MuiTextField)(({ theme }) => {
2417
+ const COUNTRY_CODES = [
2418
+ { code: 'US', name: 'United States', flag: '🇺🇸', value: '+1' },
2419
+ { code: 'GB', name: 'United Kingdom', flag: '🇬🇧', value: '+44' },
2420
+ { code: 'CA', name: 'Canada', flag: '🇨🇦', value: '+1' },
2421
+ { code: 'AU', name: 'Australia', flag: '🇦🇺', value: '+61' },
2422
+ { code: 'VN', name: 'Vietnam', flag: '🇻🇳', value: '+84' },
2423
+ { code: 'JP', name: 'Japan', flag: '🇯🇵', value: '+81' },
2424
+ { code: 'CN', name: 'China', flag: '🇨🇳', value: '+86' },
2425
+ { code: 'IN', name: 'India', flag: '🇮🇳', value: '+91' },
2426
+ { code: 'DE', name: 'Germany', flag: '🇩🇪', value: '+49' },
2427
+ { code: 'FR', name: 'France', flag: '🇫🇷', value: '+33' },
2428
+ ];
2429
+ const StyledTextField$1 = styles.styled(MuiTextField)(({ theme }) => {
1745
2430
  return {
1746
2431
  '& .MuiOutlinedInput-root': {
1747
2432
  '& fieldset': { borderColor: COLOR_NEUTRAL[300] },
@@ -1783,8 +2468,250 @@ styles.styled(MuiTextField)(({ theme }) => {
1783
2468
  },
1784
2469
  };
1785
2470
  });
2471
+ const PhoneNumberFieldComponent = ({ label = 'Số điện thoại', placeholder = '0123 456 789', value, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, helperText, onChange, countryCode = 'US', onCountryCodeChange, countries = COUNTRY_CODES, sx, ...props }) => {
2472
+ const handleCountryChange = (e) => {
2473
+ const newCode = e.target.value;
2474
+ onCountryCodeChange?.(newCode);
2475
+ };
2476
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
2477
+ display: 'block',
2478
+ ...TYPOGRAPHY.textFieldLabel,
2479
+ color: COLOR_GRAY[800],
2480
+ marginBottom: '4px',
2481
+ }, children: label })), jsxRuntime.jsx(StyledTextField$1, { placeholder: placeholder, value: value, disabled: disabled, error: error, helperText: error ? errorMessage : helperText, size: "small", fullWidth: true, onChange: onChange, InputProps: {
2482
+ startAdornment: (jsxRuntime.jsx(material.InputAdornment, { position: "start", sx: { mr: 0 }, children: jsxRuntime.jsx(material.Select, { value: countryCode, onChange: handleCountryChange, disabled: disabled, variant: "standard", sx: {
2483
+ border: 'none',
2484
+ outline: 'none',
2485
+ '& .MuiSelect-standard': { border: 'none' },
2486
+ '&.MuiInput-underline:before': { borderBottom: 'none' },
2487
+ '&.MuiInput-underline:hover:before': { borderBottom: 'none' },
2488
+ '&.MuiInput-underline:after': { borderBottom: 'none' },
2489
+ minWidth: '50px',
2490
+ fontSize: '14px',
2491
+ color: COLOR_GRAY[500],
2492
+ display: 'flex',
2493
+ alignItems: 'center',
2494
+ gap: 0.5,
2495
+ }, children: countries.map((c) => (jsxRuntime.jsx(material.MenuItem, { value: c.code, children: c.code }, c.code))) }) })),
2496
+ endAdornment: (success || error) && (jsxRuntime.jsx(material.InputAdornment, { position: "end", children: jsxRuntime.jsx(IconElement, { icon: error ? 'info' : 'check_circle', sx: { color: error ? COLOR_ERROR[500] : COLOR_SUCCESS[500] } }) })),
2497
+ }, sx: {
2498
+ '& .MuiOutlinedInput-root': {
2499
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
2500
+ ...(success && {
2501
+ '&.Mui-focused': {
2502
+ boxShadow: `0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px ${COLOR_SUCCESS[100]}`,
2503
+ },
2504
+ }),
2505
+ },
2506
+ } }), success && !error && successMessage && (jsxRuntime.jsx(material.Typography, { sx: {
2507
+ ...TYPOGRAPHY.textFieldHelper,
2508
+ color: COLOR_SUCCESS[600],
2509
+ marginTop: '4px',
2510
+ }, children: successMessage }))] }));
2511
+ };
2512
+
2513
+ const PIN_SIZES = {
2514
+ sm: { width: 40, height: 40, fontSize: 18 },
2515
+ md: { width: 48, height: 48, fontSize: 20 },
2516
+ lg: { width: 56, height: 56, fontSize: 24 },
2517
+ };
2518
+ const PIN_SPACING = {
2519
+ sm: 8,
2520
+ md: 12,
2521
+ lg: 16,
2522
+ };
1786
2523
 
1787
- material.styled(material.Autocomplete)(({ theme }) => ({
2524
+ const PINComponent = ({ length = 6, value, onChange, label, error = false, errorMessage, type = 'text', disabled = false, autoFocus = false, onComplete, align = 'left', spacing = 'md', size = 'md', masked = false, borderFocusColor, sx, }) => {
2525
+ const { palette } = material.useTheme();
2526
+ const inputRefs = React.useRef([]);
2527
+ React.useEffect(() => {
2528
+ if (autoFocus && inputRefs.current[0]) {
2529
+ inputRefs.current[0].focus();
2530
+ }
2531
+ }, [autoFocus]);
2532
+ const handleChange = (index, val) => {
2533
+ if (!/^\d*$/.test(val))
2534
+ return;
2535
+ const newValue = value.split('');
2536
+ newValue[index] = val;
2537
+ const updatedValue = newValue.join('').slice(0, length);
2538
+ onChange(updatedValue);
2539
+ if (val && index < length - 1) {
2540
+ inputRefs.current[index + 1]?.focus();
2541
+ }
2542
+ if (updatedValue.length === length) {
2543
+ onComplete?.(updatedValue);
2544
+ }
2545
+ };
2546
+ const handleKeyDown = (index, e) => {
2547
+ if (e.key === 'Backspace' && !value[index] && index > 0) {
2548
+ inputRefs.current[index - 1]?.focus();
2549
+ }
2550
+ };
2551
+ const renderPINDisplay = (index) => {
2552
+ const inputValue = value[index] || '';
2553
+ const isFilled = !!inputValue;
2554
+ const sizeStyle = PIN_SIZES[size];
2555
+ const borderColor = error ? palette.error.main : COLOR_GRAY[200];
2556
+ const borderFocusColorValue = borderFocusColor || (error ? palette.error.main : COLOR_GRAY[900]);
2557
+ if (type === 'bullet') {
2558
+ return (jsxRuntime.jsxs(material.Box, { sx: { position: 'relative', width: sizeStyle.width, height: sizeStyle.height }, children: [jsxRuntime.jsx(material.TextField, { ref: (el) => {
2559
+ const input = el?.querySelector('input');
2560
+ if (input) {
2561
+ inputRefs.current[index] = input;
2562
+ }
2563
+ }, type: "text", inputMode: "numeric", value: inputValue, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), disabled: disabled, error: error, sx: {
2564
+ width: '100%',
2565
+ height: '100%',
2566
+ '& .MuiOutlinedInput-root': {
2567
+ height: '100%',
2568
+ padding: 0,
2569
+ '& input': {
2570
+ textAlign: 'center',
2571
+ fontSize: sizeStyle.fontSize,
2572
+ fontWeight: 600,
2573
+ padding: 0,
2574
+ color: masked && isFilled ? 'transparent' : 'inherit',
2575
+ WebkitTextFillColor: masked && isFilled ? 'transparent' : 'unset',
2576
+ caretColor: palette.primary.main,
2577
+ '&::placeholder': {
2578
+ color: palette.action.disabled,
2579
+ opacity: 1,
2580
+ },
2581
+ },
2582
+ '& fieldset': {
2583
+ borderColor: borderColor,
2584
+ borderRadius: '8px',
2585
+ },
2586
+ '&:hover fieldset': {
2587
+ borderColor: error ? palette.error.main : borderFocusColorValue,
2588
+ },
2589
+ '&.Mui-focused fieldset': {
2590
+ borderColor: borderFocusColorValue,
2591
+ borderWidth: 1,
2592
+ },
2593
+ },
2594
+ '& input': {
2595
+ maxLength: 1,
2596
+ },
2597
+ }, placeholder: "-" }), masked && isFilled && (jsxRuntime.jsx(material.Box, { sx: {
2598
+ position: 'absolute',
2599
+ top: '50%',
2600
+ left: '50%',
2601
+ transform: 'translate(-50%, -50%)',
2602
+ fontSize: sizeStyle.fontSize,
2603
+ fontWeight: 600,
2604
+ color: error ? palette.error.main : palette.text.primary,
2605
+ pointerEvents: 'none',
2606
+ }, children: "\u25CF" }))] }));
2607
+ }
2608
+ if (type === 'circle') {
2609
+ return (jsxRuntime.jsxs(material.Box, { sx: { position: 'relative', width: sizeStyle.width, height: sizeStyle.height }, children: [jsxRuntime.jsx(material.TextField, { ref: (el) => {
2610
+ const input = el?.querySelector('input');
2611
+ if (input) {
2612
+ inputRefs.current[index] = input;
2613
+ }
2614
+ }, type: "text", inputMode: "numeric", value: inputValue, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), disabled: disabled, error: error, sx: {
2615
+ width: '100%',
2616
+ height: '100%',
2617
+ '& .MuiOutlinedInput-root': {
2618
+ height: '100%',
2619
+ padding: 0,
2620
+ borderRadius: '50%',
2621
+ '& input': {
2622
+ textAlign: 'center',
2623
+ fontSize: sizeStyle.fontSize,
2624
+ fontWeight: 600,
2625
+ padding: 0,
2626
+ color: masked && isFilled ? 'transparent' : 'inherit',
2627
+ WebkitTextFillColor: masked && isFilled ? 'transparent' : 'unset',
2628
+ caretColor: palette.primary.main,
2629
+ '&::placeholder': {
2630
+ color: palette.action.disabled,
2631
+ opacity: 1,
2632
+ },
2633
+ },
2634
+ '& fieldset': {
2635
+ borderColor: borderColor,
2636
+ borderRadius: '50%',
2637
+ },
2638
+ '&:hover fieldset': {
2639
+ borderColor: error ? palette.error.main : borderFocusColorValue,
2640
+ },
2641
+ '&.Mui-focused fieldset': {
2642
+ borderColor: borderFocusColorValue,
2643
+ borderWidth: 1,
2644
+ },
2645
+ },
2646
+ '& input': {
2647
+ maxLength: 1,
2648
+ },
2649
+ }, placeholder: "-" }), masked && isFilled && (jsxRuntime.jsx(material.Box, { sx: {
2650
+ position: 'absolute',
2651
+ top: '50%',
2652
+ left: '50%',
2653
+ transform: 'translate(-50%, -50%)',
2654
+ fontSize: sizeStyle.fontSize,
2655
+ fontWeight: 600,
2656
+ color: error ? palette.error.main : palette.text.primary,
2657
+ pointerEvents: 'none',
2658
+ }, children: "\u25CF" }))] }));
2659
+ }
2660
+ // Default text type
2661
+ return (jsxRuntime.jsx(material.TextField, { ref: (el) => {
2662
+ const input = el?.querySelector('input');
2663
+ if (input) {
2664
+ inputRefs.current[index] = input;
2665
+ }
2666
+ }, type: "text", inputMode: "numeric", value: inputValue, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), disabled: disabled, error: error, sx: {
2667
+ width: sizeStyle.width,
2668
+ '& .MuiOutlinedInput-root': {
2669
+ height: sizeStyle.height,
2670
+ padding: 0,
2671
+ '& input': {
2672
+ textAlign: 'center',
2673
+ fontSize: sizeStyle.fontSize,
2674
+ fontWeight: 600,
2675
+ padding: 0,
2676
+ '&::placeholder': {
2677
+ color: palette.action.disabled,
2678
+ opacity: 1,
2679
+ },
2680
+ },
2681
+ '& fieldset': {
2682
+ borderColor: borderColor,
2683
+ },
2684
+ '&:hover fieldset': {
2685
+ borderColor: error ? palette.error.main : borderFocusColorValue,
2686
+ },
2687
+ '&.Mui-focused fieldset': {
2688
+ borderColor: borderFocusColorValue,
2689
+ borderWidth: 1,
2690
+ },
2691
+ },
2692
+ '& input': {
2693
+ maxLength: 1,
2694
+ },
2695
+ }, placeholder: "-" }));
2696
+ };
2697
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Box, { sx: {
2698
+ mb: 1,
2699
+ fontSize: 14,
2700
+ fontWeight: 500,
2701
+ color: palette.text.primary,
2702
+ }, children: label })), jsxRuntime.jsx(material.Box, { sx: {
2703
+ display: 'flex',
2704
+ gap: `${PIN_SPACING[spacing]}px`,
2705
+ justifyContent: align === 'center' ? 'center' : align === 'right' ? 'flex-end' : 'flex-start',
2706
+ }, children: Array.from({ length }).map((_, index) => (jsxRuntime.jsx(material.Box, { children: renderPINDisplay(index) }, index))) }), error && errorMessage && (jsxRuntime.jsx(material.Box, { sx: {
2707
+ mt: 1,
2708
+ fontSize: 12,
2709
+ color: palette.error.main,
2710
+ textAlign: align,
2711
+ }, children: errorMessage }))] }));
2712
+ };
2713
+
2714
+ const StyledAutocomplete$1 = material.styled(material.Autocomplete)(({ theme }) => ({
1788
2715
  '& .MuiOutlinedInput-root': {
1789
2716
  padding: '8px !important',
1790
2717
  display: 'flex',
@@ -1845,8 +2772,138 @@ material.styled(material.Autocomplete)(({ theme }) => ({
1845
2772
  },
1846
2773
  },
1847
2774
  }));
2775
+ const SearchDropdownComponent = ({ value, onChange, onClear, onInputChange, onSearch, borderRadius = 6, disabled = false, multiple = false, label = '', placeholder = 'Search...', error = false, errorMessage, success = false, successMessage, helperText = '', options = [], loading = false, sx, }) => {
2776
+ const DEBOUNCE_DELAY = 500;
2777
+ const [inputValue, setInputValue] = React.useState('');
2778
+ const [filteredOptions, setFilteredOptions] = React.useState(options);
2779
+ const [isLoading, setIsLoading] = React.useState(false);
2780
+ const debounceTimerRef = React.useRef(null);
2781
+ const onSearchRef = React.useRef(onSearch);
2782
+ const onInputChangeRef = React.useRef(onInputChange);
2783
+ const optionsRef = React.useRef(options);
2784
+ // Update refs when props change
2785
+ React.useEffect(() => {
2786
+ onSearchRef.current = onSearch;
2787
+ onInputChangeRef.current = onInputChange;
2788
+ optionsRef.current = options;
2789
+ }, [onSearch, onInputChange, options]);
2790
+ // Normalize value to array for internal state
2791
+ const selectedValues = React.useMemo(() => {
2792
+ if (!value)
2793
+ return [];
2794
+ const values = Array.isArray(value) ? value : [value];
2795
+ return values.map((v) => (typeof v === 'object' ? v : { label: String(v), value: v }));
2796
+ }, [value]);
2797
+ // Search logic with debounce
2798
+ React.useEffect(() => {
2799
+ if (debounceTimerRef.current) {
2800
+ clearTimeout(debounceTimerRef.current);
2801
+ }
2802
+ // Reset to original options when input is empty
2803
+ if (!inputValue.trim()) {
2804
+ setFilteredOptions(optionsRef.current);
2805
+ return;
2806
+ }
2807
+ debounceTimerRef.current = setTimeout(async () => {
2808
+ const searchFn = onSearchRef.current;
2809
+ if (searchFn) {
2810
+ // Async search
2811
+ setIsLoading(true);
2812
+ try {
2813
+ const results = await searchFn(inputValue);
2814
+ setFilteredOptions(results);
2815
+ }
2816
+ catch (error) {
2817
+ console.error('Search error:', error);
2818
+ setFilteredOptions([]);
2819
+ }
2820
+ finally {
2821
+ setIsLoading(false);
2822
+ }
2823
+ }
2824
+ else {
2825
+ // Local filtering
2826
+ const filtered = optionsRef.current.filter((opt) => opt.label.toLowerCase().includes(inputValue.toLowerCase()));
2827
+ setFilteredOptions(filtered);
2828
+ }
2829
+ onInputChangeRef.current?.(inputValue);
2830
+ }, DEBOUNCE_DELAY);
2831
+ return () => {
2832
+ if (debounceTimerRef.current) {
2833
+ clearTimeout(debounceTimerRef.current);
2834
+ }
2835
+ };
2836
+ }, [inputValue]);
2837
+ const handleInputChange = (event, newInputValue) => {
2838
+ setInputValue(newInputValue);
2839
+ };
2840
+ const handleChange = (event, newValue) => {
2841
+ if (multiple) {
2842
+ const result = Array.isArray(newValue) ? newValue : newValue ? [newValue] : [];
2843
+ onChange?.(result.length > 0 ? result : null);
2844
+ }
2845
+ else {
2846
+ onChange?.(newValue || null);
2847
+ }
2848
+ };
2849
+ const handleClear = () => {
2850
+ setInputValue('');
2851
+ setFilteredOptions(optionsRef.current);
2852
+ onClear?.();
2853
+ };
2854
+ return (jsxRuntime.jsxs(material.Box, { sx: { width: '100%', ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { variant: "subtitle2", sx: {
2855
+ fontWeight: 500,
2856
+ color: COLOR_GRAY[900],
2857
+ marginBottom: '6px',
2858
+ display: 'block',
2859
+ }, children: label })), jsxRuntime.jsx(StyledAutocomplete$1, { multiple: multiple, freeSolo: true, options: filteredOptions, getOptionLabel: (option) => {
2860
+ if (!option)
2861
+ return '';
2862
+ if (typeof option === 'object' && 'label' in option)
2863
+ return option.label;
2864
+ return String(option);
2865
+ }, isOptionEqualToValue: (option, val) => {
2866
+ if (!option || !val)
2867
+ return false;
2868
+ if (typeof option === 'object' && typeof val === 'object' && 'value' in option && 'value' in val) {
2869
+ return option.value === val.value;
2870
+ }
2871
+ return false;
2872
+ }, value: multiple ? selectedValues : selectedValues[0] || null, inputValue: inputValue, onInputChange: handleInputChange, onChange: handleChange, disabled: disabled || loading, loading: isLoading || loading, noOptionsText: inputValue ? 'No results found' : 'Type to search', sx: {
2873
+ '& .MuiOutlinedInput-root': {
2874
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
2875
+ borderColor: error ? COLOR_ERROR[500] : success ? COLOR_SUCCESS[500] : undefined,
2876
+ },
2877
+ }, renderInput: (params) => (jsxRuntime.jsx(material.TextField, { ...params, placeholder: placeholder, variant: "outlined", size: "small", error: error, InputProps: {
2878
+ ...params.InputProps,
2879
+ startAdornment: (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(material.InputAdornment, { position: "start", sx: { marginLeft: '4px', marginRight: '0px' }, children: jsxRuntime.jsx(SearchIcon, { sx: { color: '#999', fontSize: '18px' } }) }), params.InputProps?.startAdornment] })),
2880
+ } })), renderTags: (value, getTagProps) => value.map((option, index) => {
2881
+ const label = typeof option === 'object' && option && 'label' in option ? option.label : String(option);
2882
+ return jsxRuntime.jsx(material.Chip, { ...getTagProps({ index }), label: label, size: "small" });
2883
+ }), renderOption: (props, option) => {
2884
+ const { key, ...otherProps } = props;
2885
+ const label = option?.label || '';
2886
+ return (jsxRuntime.jsx(material.Box, { ...otherProps, component: "li", children: label }, key));
2887
+ }, componentsProps: {
2888
+ clearIndicator: {
2889
+ onClick: handleClear,
2890
+ },
2891
+ } }), error && errorMessage && (jsxRuntime.jsx(material.Box, { sx: {
2892
+ fontSize: '12px',
2893
+ color: COLOR_ERROR[500],
2894
+ marginTop: '4px',
2895
+ }, children: errorMessage })), success && successMessage && (jsxRuntime.jsx(material.Box, { sx: {
2896
+ fontSize: '12px',
2897
+ color: COLOR_SUCCESS[500],
2898
+ marginTop: '4px',
2899
+ }, children: successMessage })), helperText && !error && !success && (jsxRuntime.jsx(material.Box, { sx: {
2900
+ fontSize: '12px',
2901
+ color: COLOR_NEUTRAL[500],
2902
+ marginTop: '4px',
2903
+ }, children: helperText }))] }));
2904
+ };
1848
2905
 
1849
- material.styled(material.Autocomplete)(({ theme }) => ({
2906
+ const StyledAutocomplete = material.styled(material.Autocomplete)(({ theme }) => ({
1850
2907
  '& .MuiOutlinedInput-root': {
1851
2908
  padding: '0 !important',
1852
2909
  display: 'flex',
@@ -1885,6 +2942,45 @@ material.styled(material.Autocomplete)(({ theme }) => ({
1885
2942
  paddingRight: '8px',
1886
2943
  },
1887
2944
  }));
2945
+ const SearchFieldComponent = ({ value, onChange, onClear, onInputChange, borderRadius = 6, disabled = false, placeholder = 'Placeholder', sx, }) => {
2946
+ const DEBOUNCE_DELAY = 1000;
2947
+ const [inputValue, setInputValue] = React.useState('');
2948
+ const debounceTimer = React.useRef(null);
2949
+ React.useEffect(() => {
2950
+ if (debounceTimer.current) {
2951
+ clearTimeout(debounceTimer.current);
2952
+ }
2953
+ debounceTimer.current = setTimeout(() => {
2954
+ onInputChange?.(new Event('debounce'), inputValue, 'debounce');
2955
+ }, DEBOUNCE_DELAY);
2956
+ return () => {
2957
+ if (debounceTimer.current) {
2958
+ clearTimeout(debounceTimer.current);
2959
+ }
2960
+ };
2961
+ }, [inputValue, onInputChange]);
2962
+ const handleInputChange = React.useCallback((event, value) => {
2963
+ setInputValue(value);
2964
+ }, []);
2965
+ const handleClear = React.useCallback(() => {
2966
+ setInputValue('');
2967
+ onClear?.();
2968
+ onInputChange?.(new Event('clear'), '', 'clear');
2969
+ }, [onClear, onInputChange]);
2970
+ return (jsxRuntime.jsx(StyledAutocomplete, { freeSolo: true, options: [], inputValue: inputValue, onInputChange: handleInputChange, disabled: disabled, onChange: onChange, noOptionsText: null, sx: {
2971
+ '& .MuiOutlinedInput-root': {
2972
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
2973
+ },
2974
+ ...sx,
2975
+ }, renderInput: (params) => (jsxRuntime.jsx(material.TextField, { ...params, placeholder: placeholder, variant: "outlined", size: "small", InputProps: {
2976
+ ...params.InputProps,
2977
+ startAdornment: (jsxRuntime.jsx(material.InputAdornment, { position: "start", sx: { marginLeft: '8px' }, children: jsxRuntime.jsx(SearchIcon, { sx: { color: '#999', fontSize: '20px' } }) })),
2978
+ } })), componentsProps: {
2979
+ clearIndicator: {
2980
+ onClick: handleClear,
2981
+ },
2982
+ } }));
2983
+ };
1888
2984
 
1889
2985
  const SWITCH_SIZE = {
1890
2986
  small: { width: '36px', height: '20px', thumbSize: '16px' },
@@ -1904,7 +3000,7 @@ const SWITCH_COLORS = {
1904
3000
  thumbFocusColor: '#F4EBFF',
1905
3001
  },
1906
3002
  };
1907
- material.styled(material.Switch, {
3003
+ const StyledSwitch = material.styled(material.Switch, {
1908
3004
  shouldForwardProp: (prop) => prop !== 'size',
1909
3005
  })(({ theme, size = 'medium' }) => {
1910
3006
  const mode = theme.palette.mode;
@@ -1957,7 +3053,61 @@ material.styled(material.Switch, {
1957
3053
  },
1958
3054
  };
1959
3055
  });
3056
+ const SwitchComponent = ({ title, sx, ...switchProps }) => {
3057
+ if (!title) {
3058
+ return jsxRuntime.jsx(StyledSwitch, { disableRipple: true, ...switchProps });
3059
+ }
3060
+ return (jsxRuntime.jsxs(StackRowAlignCenterJustEnd, { sx: {
3061
+ display: 'inline-flex',
3062
+ alignItems: 'center',
3063
+ gap: '12px',
3064
+ ...sx,
3065
+ }, children: [jsxRuntime.jsx(StyledSwitch, { disableRipple: true, ...switchProps }), title] }));
3066
+ };
1960
3067
 
3068
+ const TAB_STYLES = {
3069
+ position: 'relative',
3070
+ padding: '18px 16px',
3071
+ cursor: 'pointer',
3072
+ minHeight: 44,
3073
+ '&:hover': {
3074
+ bgcolor: '#F3F4F6',
3075
+ },
3076
+ };
3077
+ const TAB_UNDERLINE_STYLES = {
3078
+ width: '1px',
3079
+ alignSelf: 'stretch',
3080
+ bgcolor: '#E5E7EB',
3081
+ };
3082
+ const TABS_CONTAINER_HORIZONTAL = {
3083
+ display: 'flex',
3084
+ alignItems: 'center',
3085
+ borderBottom: '2px solid #E5E7EB',
3086
+ };
3087
+ const TAB_ACTIVE_BACKGROUND_HORIZONTAL = {
3088
+ position: 'absolute',
3089
+ bottom: -2,
3090
+ left: 0,
3091
+ right: 0,
3092
+ height: '2px',
3093
+ bgcolor: '#0F766E',
3094
+ };
3095
+ const TABS_CONTAINER_VERTICAL = {
3096
+ position: 'relative',
3097
+ padding: '10px',
3098
+ cursor: 'pointer',
3099
+ minHeight: 40,
3100
+ '&:hover': {
3101
+ bgcolor: '#F3F4F6',
3102
+ },
3103
+ width: '100%',
3104
+ };
3105
+ const TAB_ACTIVE_BACKGROUND_VERTICAL = {
3106
+ position: 'absolute',
3107
+ inset: 0,
3108
+ bgcolor: '#E6EEED',
3109
+ borderRadius: 1,
3110
+ };
1961
3111
  var TabColors;
1962
3112
  (function (TabColors) {
1963
3113
  TabColors["ACTIVE_TEXT"] = "#0F766E";
@@ -1966,7 +3116,171 @@ var TabColors;
1966
3116
  TabColors["MENU_ACTIVE_BACKGROUND"] = "#E0F2FE";
1967
3117
  })(TabColors || (TabColors = {}));
1968
3118
 
1969
- styles.styled(MuiTextField)(({ theme }) => {
3119
+ const TabsComponent = ({ idSelect, tabs, size, direction = 'row', maxDisplay, onChange, sx, sxTabs, sxWrapper, }) => {
3120
+ // state
3121
+ const [selected, setSelected] = React.useState(idSelect);
3122
+ const [anchorEl, setAnchorEl] = React.useState(null);
3123
+ const layoutGroupId = React.useId();
3124
+ React.useEffect(() => {
3125
+ setSelected(idSelect);
3126
+ }, [idSelect]);
3127
+ const isVertical = direction === 'column';
3128
+ const showOverflow = !isVertical && maxDisplay && tabs.length > maxDisplay;
3129
+ const visibleTabs = showOverflow ? tabs.slice(0, maxDisplay) : tabs;
3130
+ const overflowTabs = showOverflow ? tabs.slice(maxDisplay) : [];
3131
+ // function
3132
+ const handleOpenDropdown = (event) => {
3133
+ setAnchorEl(event.currentTarget);
3134
+ };
3135
+ const handleTabClick = (tab) => {
3136
+ setSelected(tab.id);
3137
+ onChange?.(tab.id);
3138
+ if (tab.onClick) {
3139
+ tab.onClick();
3140
+ }
3141
+ };
3142
+ const handleOverflowItemClick = (tab) => {
3143
+ handleTabClick(tab);
3144
+ setAnchorEl(null);
3145
+ };
3146
+ return (jsxRuntime.jsx(React.Fragment, { children: isVertical ? (jsxRuntime.jsx(framerMotion.LayoutGroup, { id: layoutGroupId, children: jsxRuntime.jsx(material.Stack, { direction: "column", sx: { width: 'fit-content', gap: PADDING_GAP_ITEM_SMALL, ...sxWrapper }, children: tabs.map((tab) => {
3147
+ const isActive = tab.id === selected;
3148
+ return (jsxRuntime.jsx(LinkElement, { href: tab.href, onClick: tab.onClick, id: tab.id, children: jsxRuntime.jsxs(material.Box, { sx: { position: 'relative' }, children: [jsxRuntime.jsx(material.Stack, { component: framerMotion.motion.div, sx: {
3149
+ ...TABS_CONTAINER_VERTICAL,
3150
+ color: isActive ? TabColors.ACTIVE_TEXT : TabColors.INACTIVE_TEXT,
3151
+ }, onTap: () => handleTabClick(tab), children: jsxRuntime.jsxs(material.Box, { sx: {
3152
+ ...TYPOGRAPHY_STYLES.textMd.medium,
3153
+ display: 'flex',
3154
+ alignItems: 'center',
3155
+ gap: tab.icon ? 0.5 : 0,
3156
+ position: 'relative',
3157
+ zIndex: 1,
3158
+ ...sx,
3159
+ }, children: [tab.icon && jsxRuntime.jsx(IconElement, { size: size, icon: tab.icon }), tab.name] }) }), isActive && (jsxRuntime.jsx(material.Box, { component: framerMotion.motion.div, sx: { ...TAB_ACTIVE_BACKGROUND_VERTICAL }, layoutId: `${layoutGroupId}-background` }))] }) }, tab.id));
3160
+ }) }) })) : (jsxRuntime.jsx(framerMotion.LayoutGroup, { id: layoutGroupId, children: jsxRuntime.jsxs(material.Box, { sx: { position: 'relative', display: 'flex', alignItems: 'center' }, children: [jsxRuntime.jsxs(material.Box, { sx: { ...TABS_CONTAINER_HORIZONTAL }, children: [visibleTabs.map((tab) => {
3161
+ const isActive = tab.id === selected;
3162
+ return (jsxRuntime.jsx(LinkElement, { href: tab.href, onClick: tab.onClick, id: tab.id, children: jsxRuntime.jsxs(material.Stack, { component: framerMotion.motion.div, sx: {
3163
+ color: isActive ? TabColors.ACTIVE_TEXT : TabColors.INACTIVE_TEXT,
3164
+ position: 'relative',
3165
+ padding: '18px 16px',
3166
+ cursor: 'pointer',
3167
+ minHeight: 40,
3168
+ '&:hover': {
3169
+ bgcolor: TabColors.HOVER_BACKGROUND,
3170
+ },
3171
+ ...sxTabs,
3172
+ }, onTap: () => handleTabClick(tab), children: [jsxRuntime.jsxs(material.Box, { sx: {
3173
+ ...TYPOGRAPHY_STYLES.textMd.medium,
3174
+ display: 'flex',
3175
+ alignItems: 'center',
3176
+ gap: tab.icon ? 0.5 : 0,
3177
+ ...sx,
3178
+ }, children: [tab.icon && jsxRuntime.jsx(IconElement, { size: size, icon: tab.icon }), tab.name] }), isActive && (jsxRuntime.jsx(material.Box, { component: framerMotion.motion.div, sx: { ...TAB_ACTIVE_BACKGROUND_HORIZONTAL }, layoutId: `${layoutGroupId}-underline` }))] }) }, tab.id));
3179
+ }), showOverflow && (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(material.Box, { sx: { ...TAB_UNDERLINE_STYLES } }), jsxRuntime.jsx(material.Stack, { sx: {
3180
+ ...TAB_STYLES,
3181
+ }, onClick: handleOpenDropdown, children: jsxRuntime.jsx(IconElement, { icon: "more_horiz", size: size }) })] }))] }), jsxRuntime.jsx(material.Menu, { disableScrollLock: true, anchorEl: anchorEl, open: Boolean(anchorEl), onClose: () => setAnchorEl(null), anchorOrigin: {
3182
+ vertical: 'bottom',
3183
+ horizontal: 'left',
3184
+ }, transformOrigin: {
3185
+ vertical: 'top',
3186
+ horizontal: 'left',
3187
+ }, children: overflowTabs.map((tab) => {
3188
+ const isActive = tab.id === selected;
3189
+ return (jsxRuntime.jsx(material.MenuItem, { onClick: () => handleOverflowItemClick(tab), sx: {
3190
+ color: isActive ? TabColors.ACTIVE_TEXT : TabColors.INACTIVE_TEXT,
3191
+ bgcolor: isActive ? TabColors.MENU_ACTIVE_BACKGROUND : 'transparent',
3192
+ '&:hover': {
3193
+ bgcolor: isActive ? TabColors.MENU_ACTIVE_BACKGROUND : TabColors.HOVER_BACKGROUND,
3194
+ },
3195
+ }, children: jsxRuntime.jsxs(material.Box, { sx: {
3196
+ display: 'flex',
3197
+ alignItems: 'center',
3198
+ gap: tab.icon ? 0.5 : 0,
3199
+ }, children: [tab.icon && jsxRuntime.jsx(IconElement, { size: size, icon: tab.icon }), tab.name] }) }, tab.id));
3200
+ }) })] }) })) }));
3201
+ };
3202
+
3203
+ const TextAreaComponent = ({ label = '', placeholder = '', value = '', disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, onChange, onBlur, helperText = '', rows = 4, maxLength, sx, }) => {
3204
+ const borderRadiusValue = borderRadius === 'max' ? '100px' : `${borderRadius}px`;
3205
+ const getHelperText = () => {
3206
+ if (error && errorMessage)
3207
+ return errorMessage;
3208
+ if (success && successMessage)
3209
+ return successMessage;
3210
+ if (helperText)
3211
+ return helperText;
3212
+ return '';
3213
+ };
3214
+ const getHelperTextColor = () => {
3215
+ if (error)
3216
+ return COLOR_ERROR[500];
3217
+ if (success)
3218
+ return COLOR_SUCCESS[500];
3219
+ return COLOR_NEUTRAL[400];
3220
+ };
3221
+ const getBorderColor = () => {
3222
+ if (error)
3223
+ return COLOR_ERROR[500];
3224
+ if (success)
3225
+ return COLOR_SUCCESS[500];
3226
+ return COLOR_NEUTRAL[300];
3227
+ };
3228
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
3229
+ display: 'block',
3230
+ ...TYPOGRAPHY.textFieldLabel,
3231
+ color: COLOR_GRAY[800],
3232
+ marginBottom: '4px',
3233
+ }, children: label })), jsxRuntime.jsxs(material.Box, { sx: { position: 'relative' }, children: [jsxRuntime.jsx(material.TextField, { fullWidth: true, multiline: true, rows: rows, placeholder: placeholder, value: value, disabled: disabled, onChange: (e) => onChange?.(e.target.value), onBlur: (e) => onBlur?.(e.target.value), inputProps: {
3234
+ maxLength: maxLength,
3235
+ style: {
3236
+ ...TYPOGRAPHY.text14Regular,
3237
+ paddingBottom: maxLength ? '24px' : '0px',
3238
+ },
3239
+ }, sx: {
3240
+ '& .MuiOutlinedInput-root': {
3241
+ borderRadius: borderRadiusValue,
3242
+ backgroundColor: disabled ? COLOR_NEUTRAL[100] : 'white',
3243
+ transition: 'all 0.2s ease',
3244
+ '& fieldset': {
3245
+ borderColor: getBorderColor(),
3246
+ },
3247
+ '&:hover fieldset': {
3248
+ borderColor: disabled ? getBorderColor() : error ? COLOR_ERROR[500] : COLOR_NEUTRAL[400],
3249
+ },
3250
+ '&.Mui-focused fieldset': {
3251
+ borderColor: error ? COLOR_ERROR[500] : COLOR_NEUTRAL[400],
3252
+ borderWidth: '1.5px',
3253
+ },
3254
+ },
3255
+ '& .MuiOutlinedInput-input': {
3256
+ color: value ? COLOR_GRAY[900] : COLOR_NEUTRAL[400],
3257
+ '&::placeholder': {
3258
+ color: COLOR_NEUTRAL[400],
3259
+ opacity: 1,
3260
+ },
3261
+ '&:disabled': {
3262
+ color: COLOR_NEUTRAL[400],
3263
+ WebkitTextFillColor: COLOR_NEUTRAL[400],
3264
+ },
3265
+ },
3266
+ '& .MuiOutlinedInput-notchedOutline': {
3267
+ borderColor: getBorderColor(),
3268
+ },
3269
+ } }), maxLength && (jsxRuntime.jsxs(material.Box, { sx: {
3270
+ position: 'absolute',
3271
+ bottom: '8px',
3272
+ right: '12px',
3273
+ fontSize: '12px',
3274
+ color: COLOR_NEUTRAL[400],
3275
+ pointerEvents: 'none',
3276
+ }, children: ["(", value?.length, "/", maxLength, ")"] }))] }), getHelperText() && (jsxRuntime.jsx(material.Box, { sx: {
3277
+ color: getHelperTextColor(),
3278
+ marginTop: '4px',
3279
+ ...TYPOGRAPHY.textFieldHelper,
3280
+ }, children: getHelperText() }))] }));
3281
+ };
3282
+
3283
+ const StyledTextField = styles.styled(MuiTextField)(({ theme }) => {
1970
3284
  return {
1971
3285
  '& .MuiOutlinedInput-root': {
1972
3286
  '& fieldset': { borderColor: COLOR_NEUTRAL[300] },
@@ -2008,10 +3322,221 @@ styles.styled(MuiTextField)(({ theme }) => {
2008
3322
  },
2009
3323
  };
2010
3324
  });
3325
+ const TextFieldComponent = ({ label, placeholder = 'Placeholder', value, disabled = false, error = false, success = false, errorMessage, successMessage, borderRadius = 6, helperText, onChange, iconBefore, iconAfter, sx, ...props }) => {
3326
+ return (jsxRuntime.jsxs(material.Box, { sx: { ...sx }, children: [label && (jsxRuntime.jsx(material.Typography, { sx: {
3327
+ display: 'block',
3328
+ ...TYPOGRAPHY.textFieldLabel,
3329
+ color: COLOR_GRAY[800],
3330
+ marginBottom: '4px',
3331
+ }, children: label })), jsxRuntime.jsx(StyledTextField, { placeholder: placeholder, value: value, disabled: disabled, error: error, helperText: error ? errorMessage : helperText, size: "small", fullWidth: true, onChange: onChange, InputProps: {
3332
+ startAdornment: iconBefore ? jsxRuntime.jsx(material.InputAdornment, { position: "start", children: iconBefore }) : undefined,
3333
+ endAdornment: iconAfter ? jsxRuntime.jsx(material.InputAdornment, { position: "end", children: iconAfter }) : undefined,
3334
+ }, sx: {
3335
+ '& .MuiOutlinedInput-root': {
3336
+ borderRadius: borderRadius === 'max' ? '100px' : `${borderRadius}px`,
3337
+ ...(success && {
3338
+ '&.Mui-focused': {
3339
+ boxShadow: `0 1px 2px 0 rgba(10, 13, 18, 0.05), 0 0 0 4px ${COLOR_SUCCESS[100]}`,
3340
+ },
3341
+ }),
3342
+ },
3343
+ }, ...props }), success && !error && successMessage && (jsxRuntime.jsx(material.Typography, { sx: {
3344
+ ...TYPOGRAPHY.textFieldHelper,
3345
+ color: COLOR_SUCCESS[500],
3346
+ marginTop: '4px',
3347
+ }, children: successMessage }))] }));
3348
+ };
2011
3349
 
2012
- ({
3350
+ const SX_STYLES = {
2013
3351
  progressBar: {
2014
- backgroundColor: COLOR_GRAY[200]}});
3352
+ position: 'absolute',
3353
+ top: 0,
3354
+ left: 0,
3355
+ height: '100%',
3356
+ backgroundColor: COLOR_GRAY[200],
3357
+ opacity: 0.8,
3358
+ transition: 'width 0.3s ease, opacity 0.3s ease',
3359
+ animation: 'wave 1.5s linear infinite',
3360
+ '@keyframes wave': {
3361
+ '0%': { backgroundPosition: '0% 0%' },
3362
+ '50%': { backgroundPosition: '100% 0%' },
3363
+ '100%': { backgroundPosition: '0% 0%' },
3364
+ },
3365
+ },
3366
+ imageIcon: {
3367
+ width: '40px',
3368
+ height: '40px',
3369
+ flexShrink: 0,
3370
+ position: 'relative',
3371
+ zIndex: 1,
3372
+ },
3373
+ contentBox: {
3374
+ flexGrow: 1,
3375
+ minWidth: 0,
3376
+ position: 'relative',
3377
+ zIndex: 1,
3378
+ },
3379
+ textBox: {
3380
+ minWidth: 0,
3381
+ flexGrow: 1,
3382
+ mr: 2,
3383
+ },
3384
+ actionBox: {
3385
+ flexShrink: 0,
3386
+ display: 'flex',
3387
+ alignItems: 'center',
3388
+ position: 'relative',
3389
+ zIndex: 1,
3390
+ },
3391
+ linearProgress: {
3392
+ mt: 1,
3393
+ width: '100%',
3394
+ },
3395
+ };
3396
+
3397
+ const VIDEO_EXTENSIONS = ['mp4', 'mov', 'avi', 'wmv', 'flv', 'mkv', 'webm'];
3398
+ const ICON_PATH = {
3399
+ VIDEO: '/images/icon/film.svg',
3400
+ FILE: '/images/icon/file.svg',
3401
+ };
3402
+ // ============================================================================
3403
+ // Helper Functions
3404
+ // ============================================================================
3405
+ const formatFileSize = (bytes) => {
3406
+ if (bytes === 0)
3407
+ return '0 Bytes';
3408
+ const k = 1024;
3409
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
3410
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
3411
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
3412
+ };
3413
+ const getFileIcon = (fileName) => {
3414
+ const ext = fileName.split('.').pop()?.toLowerCase();
3415
+ return ext && VIDEO_EXTENSIONS.includes(ext) ? ICON_PATH.VIDEO : ICON_PATH.FILE;
3416
+ };
3417
+ // ============================================================================
3418
+ // Component
3419
+ // ============================================================================
3420
+ const UploaderItemComponent = ({ file, progress = 0, status = 'pending', onDelete, onRetry, isProcess = true, borderSuccess, borderError = COLOR_ERROR[600], sx, }) => {
3421
+ // Memoize
3422
+ const iconSrc = React.useMemo(() => getFileIcon(file.name), [file.name]);
3423
+ // Status flags
3424
+ const isCompleted = status === 'success';
3425
+ const isFailed = status === 'failed';
3426
+ const isUploading = status === 'uploading';
3427
+ // Determine colors based on status
3428
+ const borderColor = isFailed
3429
+ ? String(borderError)
3430
+ : isCompleted && borderSuccess
3431
+ ? String(borderSuccess)
3432
+ : '#e0e0e0';
3433
+ const textColor = isFailed ? String(borderError) : '#737373';
3434
+ const subtitleColor = isFailed ? String(borderError) : '#a3a3a3';
3435
+ // Render progress info
3436
+ const renderProgressInfo = () => {
3437
+ if (isUploading && !isCompleted)
3438
+ return ` • ${Math.round(progress)}% uploaded`;
3439
+ if (isFailed)
3440
+ return ' • Upload failed';
3441
+ return '';
3442
+ };
3443
+ return (jsxRuntime.jsxs(material.Box, { sx: {
3444
+ display: 'flex',
3445
+ alignItems: 'flex-start',
3446
+ padding: '16px',
3447
+ border: '1px solid',
3448
+ borderColor: borderColor,
3449
+ borderRadius: '8px',
3450
+ gap: '16px',
3451
+ position: 'relative',
3452
+ overflow: 'hidden',
3453
+ transition: 'background-color 0.3s ease',
3454
+ backgroundColor: 'background.paper',
3455
+ ...sx,
3456
+ }, children: [!isProcess && isUploading && !isCompleted && !isFailed && (jsxRuntime.jsx(material.Box, { sx: { ...SX_STYLES.progressBar, width: `${progress}%` } })), jsxRuntime.jsx(material.Box, { component: "img", src: iconSrc, alt: "file icon", sx: SX_STYLES.imageIcon }), jsxRuntime.jsxs(material.Box, { sx: SX_STYLES.contentBox, children: [jsxRuntime.jsxs(StackRowAlignCenterJustBetween, { children: [jsxRuntime.jsxs(material.Box, { sx: SX_STYLES.textBox, children: [jsxRuntime.jsx(material.Typography, { noWrap: true, title: file.name, sx: { ...TYPOGRAPHY.text14Medium, color: textColor }, children: file.name }), jsxRuntime.jsxs(material.Typography, { sx: { ...TYPOGRAPHY.text14Regular, color: subtitleColor }, children: [formatFileSize(file.size), renderProgressInfo()] })] }), jsxRuntime.jsxs(material.Box, { sx: SX_STYLES.actionBox, children: [!isProcess && isUploading && !isCompleted && (jsxRuntime.jsx(material.Box, { sx: { position: 'relative', display: 'inline-flex', mr: 1 }, children: jsxRuntime.jsx(material.CircularProgress, { variant: "determinate", value: progress, color: "success", size: 24 }) })), isCompleted && jsxRuntime.jsx(CheckCircleIcon, { color: "success", sx: { mr: 1 } }), isFailed && onRetry && (jsxRuntime.jsx(material.IconButton, { size: "small", onClick: onRetry, title: "Retry upload", children: jsxRuntime.jsx(RefreshIcon, { fontSize: "small", sx: { color: borderError } }) })), !isFailed && onDelete && (jsxRuntime.jsx(material.IconButton, { size: "small", onClick: onDelete, children: jsxRuntime.jsx(IconElement, { icon: "delete" }) }))] })] }), isProcess && isUploading && (jsxRuntime.jsx(material.Box, { sx: SX_STYLES.linearProgress, children: jsxRuntime.jsx(material.LinearProgress, { variant: "determinate", value: progress, color: "success", sx: { height: 8, borderRadius: 4 } }) }))] })] }));
3457
+ };
3458
+
3459
+ const UploaderComponent = ({ onFilesSelected, accept = '*', multiple = true, children, sx, labelSx, uploadLabel = 'Click to upload', appearance, files: externalFiles, onDeleteFile, onRetryFile, borderError, }) => {
3460
+ const fileInputRef = React.useRef(null);
3461
+ const [isDragging, setIsDragging] = React.useState(false);
3462
+ // Sử dụng external files nếu có, nếu không hiển thị rỗng
3463
+ const displayFiles = externalFiles || [];
3464
+ const handleClick = () => {
3465
+ fileInputRef.current?.click();
3466
+ };
3467
+ const handleFileChange = (event) => {
3468
+ const selectedFiles = event.target.files;
3469
+ if (selectedFiles) {
3470
+ const fileArray = Array.from(selectedFiles);
3471
+ onFilesSelected(fileArray);
3472
+ }
3473
+ event.target.value = '';
3474
+ };
3475
+ const handleDeleteFile = (file) => {
3476
+ if (onDeleteFile) {
3477
+ onDeleteFile(file);
3478
+ }
3479
+ };
3480
+ const handleDragOver = (e) => {
3481
+ e.preventDefault();
3482
+ e.stopPropagation();
3483
+ setIsDragging(true);
3484
+ };
3485
+ const handleDragLeave = (e) => {
3486
+ e.preventDefault();
3487
+ e.stopPropagation();
3488
+ setIsDragging(false);
3489
+ };
3490
+ const handleDrop = (e) => {
3491
+ e.preventDefault();
3492
+ e.stopPropagation();
3493
+ setIsDragging(false);
3494
+ const files = e.dataTransfer.files;
3495
+ if (files) {
3496
+ onFilesSelected(Array.from(files));
3497
+ }
3498
+ };
3499
+ return (jsxRuntime.jsxs(material.Box, { sx: {
3500
+ border: '2px solid',
3501
+ borderColor: appearance?.borderColor || 'action.selected',
3502
+ borderRadius: '8px',
3503
+ padding: '32px 24px',
3504
+ textAlign: 'center',
3505
+ cursor: 'pointer',
3506
+ transition: 'all 0.3s ease',
3507
+ backgroundColor: isDragging ? 'action.selected' : appearance?.background || 'background.paper',
3508
+ '&:hover': {
3509
+ borderColor: appearance?.borderColorHover || appearance?.borderColor || 'primary.main',
3510
+ filter: 'brightness(0.92)',
3511
+ },
3512
+ ...sx,
3513
+ }, onClick: handleClick, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: handleFileChange, style: { display: 'none' } }), displayFiles.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: children ? (jsxRuntime.jsxs(material.Box, { children: [children, jsxRuntime.jsxs(material.Box, { component: "p", sx: {
3514
+ color: 'primary.main',
3515
+ textDecoration: 'underline',
3516
+ fontWeight: 500,
3517
+ fontSize: '14px',
3518
+ marginTop: '12px',
3519
+ margin: '12px 0 0 0',
3520
+ ...labelSx,
3521
+ }, children: [uploadLabel, " or drag and drop"] })] })) : (jsxRuntime.jsxs(material.Box, { children: [jsxRuntime.jsx(material.Box, { component: "img", src: "/images/icon/uploader.svg", alt: "Upload icon", sx: {
3522
+ width: '46px',
3523
+ height: '46px',
3524
+ marginBottom: '12px',
3525
+ } }), jsxRuntime.jsxs(material.Box, { component: "p", sx: {
3526
+ color: 'primary.main',
3527
+ textDecoration: 'underline',
3528
+ fontWeight: 500,
3529
+ fontSize: '14px',
3530
+ margin: 0,
3531
+ ...labelSx,
3532
+ }, children: [uploadLabel, " or drag and drop"] })] })) })), displayFiles && displayFiles.length > 0 && (jsxRuntime.jsx(material.Box, { sx: {
3533
+ marginTop: '24px',
3534
+ display: 'flex',
3535
+ flexDirection: 'column',
3536
+ gap: '12px',
3537
+ textAlign: 'left',
3538
+ }, onClick: (e) => e.stopPropagation(), children: displayFiles.map((item, index) => (jsxRuntime.jsx(UploaderItemComponent, { file: item.file, progress: item.progress, status: item.status, isProcess: item.isProcess ?? true, onDelete: () => handleDeleteFile(item.file), onRetry: () => onRetryFile?.(item.id), borderSuccess: appearance?.borderSuccess, borderError: borderError }, item.id || index))) }))] }));
3539
+ };
2015
3540
 
2016
3541
  exports.AVATAR_SIZES = AVATAR_SIZES;
2017
3542
  exports.AvatarComponent = AvatarComponent;
@@ -2025,6 +3550,8 @@ exports.BadgeImage = BadgeImage;
2025
3550
  exports.BadgeLive = BadgeLive;
2026
3551
  exports.BadgeNumber = BadgeNumber;
2027
3552
  exports.BadgeOnline = BadgeOnline;
3553
+ exports.BreadcrumbsComponent = BreadcrumbsComponent;
3554
+ exports.ButtonBarComponent = ButtonBarComponent;
2028
3555
  exports.ButtonComponent = ButtonComponent;
2029
3556
  exports.COLOR_ACCENT = COLOR_ACCENT;
2030
3557
  exports.COLOR_BRAND = COLOR_BRAND;
@@ -2034,16 +3561,24 @@ exports.COLOR_INFO = COLOR_INFO;
2034
3561
  exports.COLOR_NEUTRAL = COLOR_NEUTRAL;
2035
3562
  exports.COLOR_SUCCESS = COLOR_SUCCESS;
2036
3563
  exports.COLOR_WARNING = COLOR_WARNING;
3564
+ exports.CheckboxComponent = CheckboxComponent;
2037
3565
  exports.CheckboxContentComponent = CheckboxContentComponent;
3566
+ exports.ChipComponent = ChipComponent;
3567
+ exports.DateFieldComponent = DateFieldComponent;
3568
+ exports.DateRangePickerComponent = DateRangePickerComponent;
2038
3569
  exports.DialogWrapper = DialogWrapper;
3570
+ exports.DropdownFieldComponent = DropdownFieldComponent;
2039
3571
  exports.FONT_FAMILY = FONT_FAMILY;
2040
3572
  exports.FONT_SIZE = FONT_SIZE;
2041
3573
  exports.FONT_STYLE = FONT_STYLE;
2042
3574
  exports.FONT_WEIGHT = FONT_WEIGHT;
3575
+ exports.GridComponent = GridComponent;
2043
3576
  exports.IconElement = IconElement;
2044
3577
  exports.ImageElement = ImageElement;
3578
+ exports.InputStepperComponent = InputStepperComponent;
2045
3579
  exports.LINE_HEIGHT = LINE_HEIGHT;
2046
3580
  exports.LinkElement = LinkElement;
3581
+ exports.LinkFieldComponent = LinkFieldComponent;
2047
3582
  exports.LinkInternalElement = LinkInternalElement;
2048
3583
  exports.MAP_SIZE = MAP_SIZE;
2049
3584
  exports.Modal = ModalComponent;
@@ -2051,11 +3586,21 @@ exports.ModalCard = ModalCardComponent;
2051
3586
  exports.ModalDescription = ModalDescription;
2052
3587
  exports.ModalIcon = ModalIcon;
2053
3588
  exports.ModalTitle = ModalTitle;
3589
+ exports.MoneyFieldComponent = MoneyFieldComponent;
3590
+ exports.PINComponent = PINComponent;
3591
+ exports.PhoneNumberFieldComponent = PhoneNumberFieldComponent;
2054
3592
  exports.SIZE_EXTRA_LARGE = SIZE_EXTRA_LARGE;
2055
3593
  exports.STYLE = style_constant;
3594
+ exports.SearchDropdownComponent = SearchDropdownComponent;
3595
+ exports.SearchFieldComponent = SearchFieldComponent;
3596
+ exports.SwitchComponent = SwitchComponent;
2056
3597
  exports.TYPOGRAPHY = TYPOGRAPHY;
2057
3598
  exports.TYPOGRAPHY_STYLES = TYPOGRAPHY_STYLES;
3599
+ exports.TabsComponent = TabsComponent;
3600
+ exports.TextAreaComponent = TextAreaComponent;
3601
+ exports.TextFieldComponent = TextFieldComponent;
2058
3602
  exports.TypographyOneLine = TypographyOneLine;
3603
+ exports.UploaderComponent = UploaderComponent;
2059
3604
  exports.createTypography = createTypography;
2060
3605
  exports.getBadgePosition = getBadgePosition;
2061
3606
  //# sourceMappingURL=index.js.map