@akinon/next 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/.editorconfig +7 -7
  2. package/.eslintrc.js +40 -40
  3. package/.gitattributes +15 -0
  4. package/.prettierrc +13 -13
  5. package/CHANGELOG.md +14 -0
  6. package/api/auth.ts +231 -231
  7. package/api/cache.ts +44 -44
  8. package/api/client.ts +174 -174
  9. package/api/logout.ts +42 -42
  10. package/bin/pz-check-dependencies.js +98 -98
  11. package/bin/pz-install-plugins.js +33 -33
  12. package/bin/pz-install-theme.js +58 -58
  13. package/bin/pz-postbuild.js +1 -1
  14. package/bin/pz-postdev.js +1 -1
  15. package/bin/pz-postinstall.js +6 -6
  16. package/bin/pz-poststart.js +1 -1
  17. package/bin/pz-prebuild.js +4 -4
  18. package/bin/pz-predev.js +4 -4
  19. package/bin/pz-prestart.js +1 -1
  20. package/bin/run-script.js +44 -44
  21. package/components/accordion.tsx +52 -52
  22. package/components/button.tsx +46 -46
  23. package/components/client-root.tsx +19 -19
  24. package/components/icon.tsx +18 -18
  25. package/components/image.tsx +133 -133
  26. package/components/index.ts +1 -0
  27. package/components/input.tsx +110 -110
  28. package/components/lazy-component.tsx +33 -33
  29. package/components/loader-spinner.tsx +23 -23
  30. package/components/mobile-app-toggler.tsx +26 -26
  31. package/components/modal.tsx +66 -0
  32. package/components/oauth-login.tsx +24 -24
  33. package/components/plugin-module.tsx +5 -0
  34. package/components/price.tsx +55 -55
  35. package/components/pz-providers.tsx +24 -24
  36. package/components/pz-root.tsx +21 -21
  37. package/components/radio.tsx +18 -18
  38. package/components/react-portal.tsx +45 -45
  39. package/components/redirect-three-d/content/index.tsx +74 -74
  40. package/components/redirect-three-d/index.tsx +17 -17
  41. package/components/selected-payment-option-view.tsx +1 -1
  42. package/components/trans.tsx +39 -39
  43. package/data/client/account.ts +208 -208
  44. package/data/client/api.ts +85 -85
  45. package/data/client/basket.ts +82 -82
  46. package/data/client/misc.ts +101 -101
  47. package/data/client/product.ts +89 -89
  48. package/data/client/user.ts +99 -99
  49. package/data/client/wishlist.ts +118 -118
  50. package/data/server/category.ts +132 -132
  51. package/data/server/flatpage.ts +21 -21
  52. package/data/server/form.ts +22 -22
  53. package/data/server/index.ts +10 -10
  54. package/data/server/landingpage.ts +24 -24
  55. package/data/server/list.ts +67 -67
  56. package/data/server/menu.ts +35 -35
  57. package/data/server/product.ts +86 -86
  58. package/data/server/seo.ts +48 -48
  59. package/data/server/special-page.ts +47 -47
  60. package/data/server/widget.ts +27 -27
  61. package/data/urls.ts +221 -221
  62. package/hocs/client/index.ts +1 -1
  63. package/hocs/client/with-segment-defaults.tsx +25 -25
  64. package/hocs/server/index.ts +1 -1
  65. package/hocs/server/with-segment-defaults.tsx +85 -85
  66. package/hooks/index.ts +10 -10
  67. package/hooks/use-captcha.tsx +76 -76
  68. package/hooks/use-common-product-attributes.ts +36 -36
  69. package/hooks/use-debounce.ts +20 -20
  70. package/hooks/use-localization.ts +78 -78
  71. package/hooks/use-media-query.ts +36 -36
  72. package/hooks/use-mobile-iframe-handler.ts +23 -23
  73. package/hooks/use-on-click-outside.tsx +28 -28
  74. package/hooks/use-payment-options.ts +3 -1
  75. package/hooks/use-router.ts +45 -45
  76. package/hooks/use-translation.ts +14 -14
  77. package/lib/cache.ts +215 -215
  78. package/localization/index.ts +5 -5
  79. package/localization/provider.tsx +58 -58
  80. package/middlewares/complete-gpay.ts +159 -0
  81. package/middlewares/currency.ts +100 -100
  82. package/middlewares/default.ts +259 -256
  83. package/middlewares/index.ts +31 -29
  84. package/middlewares/locale.ts +68 -68
  85. package/middlewares/oauth-login.ts +79 -79
  86. package/middlewares/pretty-url.ts +104 -104
  87. package/middlewares/redirection-payment.ts +160 -160
  88. package/middlewares/three-d-redirection.ts +159 -159
  89. package/middlewares/url-redirection.ts +65 -65
  90. package/package.json +2 -2
  91. package/plugins.js +1 -0
  92. package/redux/hooks.ts +7 -7
  93. package/redux/middlewares/index.ts +50 -50
  94. package/redux/reducers/checkout.ts +184 -184
  95. package/redux/reducers/config.ts +28 -28
  96. package/redux/reducers/header.ts +59 -59
  97. package/redux/reducers/root.ts +61 -61
  98. package/sentry/index.ts +27 -27
  99. package/tailwind/rtl.js +137 -137
  100. package/types/commerce/account.ts +64 -64
  101. package/types/commerce/address.ts +94 -94
  102. package/types/commerce/basket.ts +43 -43
  103. package/types/commerce/category.ts +114 -114
  104. package/types/commerce/checkout.ts +143 -143
  105. package/types/commerce/flatpage.ts +7 -7
  106. package/types/commerce/form.ts +66 -66
  107. package/types/commerce/index.ts +12 -12
  108. package/types/commerce/landingpage.ts +7 -7
  109. package/types/commerce/misc.ts +127 -127
  110. package/types/commerce/order.ts +119 -119
  111. package/types/commerce/product.ts +109 -109
  112. package/types/commerce/widget.ts +28 -28
  113. package/types/gtm.ts +16 -16
  114. package/types/index.ts +274 -274
  115. package/types/metadata.ts +7 -7
  116. package/types/next-auth.d.ts +24 -24
  117. package/utils/app-fetch.ts +69 -69
  118. package/utils/deep-merge.js +24 -24
  119. package/utils/image-loader.ts +31 -31
  120. package/utils/index.ts +150 -150
  121. package/utils/localization.ts +29 -29
  122. package/utils/log.ts +138 -138
  123. package/utils/menu-generator.ts +27 -27
  124. package/utils/mobile-3d-iframe.ts +77 -77
  125. package/utils/server-translation.ts +57 -57
  126. package/utils/server-variables.ts +9 -9
  127. package/with-pz-config.js +94 -94
@@ -1,46 +1,46 @@
1
- 'use client';
2
-
3
- import { ButtonProps } from '../types/index';
4
- import clsx from 'clsx';
5
- import { twMerge } from 'tailwind-merge';
6
-
7
- export const Button = (props: ButtonProps) => {
8
- return (
9
- <button
10
- {...props}
11
- className={twMerge(
12
- clsx(
13
- [
14
- 'px-4',
15
- 'h-10',
16
- 'text-xs',
17
- 'bg-primary',
18
- 'text-primary-foreground',
19
- 'border',
20
- 'border-primary',
21
- 'transition-all',
22
- 'hover:bg-white',
23
- 'hover:border-primary',
24
- 'hover:text-primary'
25
- ],
26
- props.appearance === 'outlined' && [
27
- 'bg-transparent ',
28
- 'text-primary ',
29
- 'hover:bg-primary ',
30
- 'hover:text-primary-foreground'
31
- ],
32
- props.appearance === 'ghost' && [
33
- 'bg-transparent',
34
- 'border-transparent',
35
- 'text-primary',
36
- 'hover:bg-primary',
37
- 'hover:text-primary-foreground'
38
- ]
39
- ),
40
- props.className
41
- )}
42
- >
43
- {props.children}
44
- </button>
45
- );
46
- };
1
+ 'use client';
2
+
3
+ import { ButtonProps } from '../types/index';
4
+ import clsx from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+
7
+ export const Button = (props: ButtonProps) => {
8
+ return (
9
+ <button
10
+ {...props}
11
+ className={twMerge(
12
+ clsx(
13
+ [
14
+ 'px-4',
15
+ 'h-10',
16
+ 'text-xs',
17
+ 'bg-primary',
18
+ 'text-primary-foreground',
19
+ 'border',
20
+ 'border-primary',
21
+ 'transition-all',
22
+ 'hover:bg-white',
23
+ 'hover:border-primary',
24
+ 'hover:text-primary'
25
+ ],
26
+ props.appearance === 'outlined' && [
27
+ 'bg-transparent ',
28
+ 'text-primary ',
29
+ 'hover:bg-primary ',
30
+ 'hover:text-primary-foreground'
31
+ ],
32
+ props.appearance === 'ghost' && [
33
+ 'bg-transparent',
34
+ 'border-transparent',
35
+ 'text-primary',
36
+ 'hover:bg-primary',
37
+ 'hover:text-primary-foreground'
38
+ ]
39
+ ),
40
+ props.className
41
+ )}
42
+ >
43
+ {props.children}
44
+ </button>
45
+ );
46
+ };
@@ -1,19 +1,19 @@
1
- 'use client';
2
-
3
- import { useMobileIframeHandler } from '../hooks';
4
-
5
- export default function ClientRoot({
6
- children,
7
- sessionId
8
- }: {
9
- children: React.ReactNode;
10
- sessionId?: string;
11
- }) {
12
- const { preventPageRender } = useMobileIframeHandler({ sessionId });
13
-
14
- if (preventPageRender) {
15
- return null;
16
- }
17
-
18
- return <>{children}</>;
19
- }
1
+ 'use client';
2
+
3
+ import { useMobileIframeHandler } from '../hooks';
4
+
5
+ export default function ClientRoot({
6
+ children,
7
+ sessionId
8
+ }: {
9
+ children: React.ReactNode;
10
+ sessionId?: string;
11
+ }) {
12
+ const { preventPageRender } = useMobileIframeHandler({ sessionId });
13
+
14
+ if (preventPageRender) {
15
+ return null;
16
+ }
17
+
18
+ return <>{children}</>;
19
+ }
@@ -1,18 +1,18 @@
1
- import { IconProps } from '../types/index';
2
- import clsx from 'clsx';
3
-
4
- export const Icon = (props: IconProps) => {
5
- const { name, size, className, ...rest } = props;
6
-
7
- return (
8
- <i
9
- className={clsx(`flex pz-icon-${name}`, className)}
10
- {...rest}
11
- style={
12
- size && {
13
- fontSize: `${size}px`
14
- }
15
- }
16
- />
17
- );
18
- };
1
+ import { IconProps } from '../types/index';
2
+ import clsx from 'clsx';
3
+
4
+ export const Icon = (props: IconProps) => {
5
+ const { name, size, className, ...rest } = props;
6
+
7
+ return (
8
+ <i
9
+ className={clsx(`flex pz-icon-${name}`, className)}
10
+ {...rest}
11
+ style={
12
+ size && {
13
+ fontSize: `${size}px`
14
+ }
15
+ }
16
+ />
17
+ );
18
+ };
@@ -1,133 +1,133 @@
1
- 'use client';
2
-
3
- import { CDNOptions } from '../types';
4
- import NextImage, { ImageProps as NextImageProps } from 'next/image';
5
- import { twMerge } from 'tailwind-merge';
6
- import { ImageLoader } from '../utils/image-loader';
7
-
8
- interface ImageProps extends NextImageProps {
9
- /**
10
- * Use fill to make the image responsive.
11
- * You also need to provide sizes and aspectRatio props.
12
- *
13
- * @default false
14
- */
15
- fill?: boolean;
16
- /**
17
- * Crop option for CDN
18
- *
19
- * Available options:
20
- * - `center`
21
- * - `top`
22
- * - `bottom`
23
- * - `left`
24
- * - `right`
25
- *
26
- * @default 'center'
27
- */
28
- crop?: CDNOptions['crop'];
29
- /**
30
- * It is used to calculate the height of the image when fill is true.
31
- * It prevents layout shift problems.
32
- */
33
- aspectRatio?: number;
34
- /**
35
- * Sizes attribute for responsive images
36
- *
37
- * If it is not provided, large images will be downloaded for small screens and it will cause performance issues.
38
- *
39
- * @example
40
- * <Image
41
- * src={src}
42
- * sizes="(min-width: 768px) 50vw, 100vw"
43
- * fill
44
- * />
45
- * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
46
- */
47
- sizes?: string;
48
- imageClassName?: string;
49
- }
50
-
51
- const DEFAULT_QUALITY = 70;
52
-
53
- /**
54
- * Image component for responsive images.
55
- *
56
- * It uses CDN options automatically if the image is hosted on Akinon CDN. You don't need to convert the src prop to CDN url.
57
- *
58
- * ## For responsive images
59
- * You need to provide `fill`, `sizes` and `aspectRatio` props.
60
- * If you are not sure about sizes, you can give `100vw` as a value. But it may cause performance issues.
61
- *
62
- * ## For non-responsive images
63
- * You need to provide `width` and `height` props.
64
- * This way, the browser will know the size of the image before downloading it and it will prevent layout shift problems.
65
- *
66
- * ## CDN options
67
- * You can use `crop` option to crop the image.
68
- *
69
- * Available options:
70
- * - `center`
71
- * - `top`
72
- * - `bottom`
73
- * - `left`
74
- * - `right`
75
- *
76
- * You can also use `quality` option to change the quality of the image.
77
- * Be careful about the file size when you change the quality.
78
- *
79
- * @default 70
80
- */
81
- export const Image = (props: ImageProps) => {
82
- const {
83
- src,
84
- width,
85
- fill,
86
- sizes,
87
- aspectRatio,
88
- quality = DEFAULT_QUALITY,
89
- crop = 'center',
90
- className,
91
- imageClassName,
92
- ...restImage
93
- } = props;
94
-
95
- const hasGif = typeof src === 'string' && src.includes('.gif');
96
-
97
- if (fill && !aspectRatio) {
98
- throw new Error('aspectRatio is required when fill is true');
99
- }
100
-
101
- if (fill && !sizes) {
102
- throw new Error('sizes is required when fill is true');
103
- }
104
-
105
- return (
106
- <div
107
- className={twMerge('relative inline-block', fill && 'w-full', className)}
108
- style={{
109
- ...(fill && { aspectRatio })
110
- }}
111
- >
112
- <NextImage
113
- {...restImage}
114
- width={width}
115
- src={src}
116
- sizes={sizes}
117
- fill={fill}
118
- loader={({ src, width }) => {
119
- return ImageLoader({
120
- src,
121
- width,
122
- quality: parseInt(String(quality), DEFAULT_QUALITY),
123
- crop,
124
- fill,
125
- aspectRatio
126
- });
127
- }}
128
- className={imageClassName}
129
- {...(hasGif && { unoptimized: true })}
130
- />
131
- </div>
132
- );
133
- };
1
+ 'use client';
2
+
3
+ import { CDNOptions } from '../types';
4
+ import NextImage, { ImageProps as NextImageProps } from 'next/image';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { ImageLoader } from '../utils/image-loader';
7
+
8
+ interface ImageProps extends NextImageProps {
9
+ /**
10
+ * Use fill to make the image responsive.
11
+ * You also need to provide sizes and aspectRatio props.
12
+ *
13
+ * @default false
14
+ */
15
+ fill?: boolean;
16
+ /**
17
+ * Crop option for CDN
18
+ *
19
+ * Available options:
20
+ * - `center`
21
+ * - `top`
22
+ * - `bottom`
23
+ * - `left`
24
+ * - `right`
25
+ *
26
+ * @default 'center'
27
+ */
28
+ crop?: CDNOptions['crop'];
29
+ /**
30
+ * It is used to calculate the height of the image when fill is true.
31
+ * It prevents layout shift problems.
32
+ */
33
+ aspectRatio?: number;
34
+ /**
35
+ * Sizes attribute for responsive images
36
+ *
37
+ * If it is not provided, large images will be downloaded for small screens and it will cause performance issues.
38
+ *
39
+ * @example
40
+ * <Image
41
+ * src={src}
42
+ * sizes="(min-width: 768px) 50vw, 100vw"
43
+ * fill
44
+ * />
45
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
46
+ */
47
+ sizes?: string;
48
+ imageClassName?: string;
49
+ }
50
+
51
+ const DEFAULT_QUALITY = 70;
52
+
53
+ /**
54
+ * Image component for responsive images.
55
+ *
56
+ * It uses CDN options automatically if the image is hosted on Akinon CDN. You don't need to convert the src prop to CDN url.
57
+ *
58
+ * ## For responsive images
59
+ * You need to provide `fill`, `sizes` and `aspectRatio` props.
60
+ * If you are not sure about sizes, you can give `100vw` as a value. But it may cause performance issues.
61
+ *
62
+ * ## For non-responsive images
63
+ * You need to provide `width` and `height` props.
64
+ * This way, the browser will know the size of the image before downloading it and it will prevent layout shift problems.
65
+ *
66
+ * ## CDN options
67
+ * You can use `crop` option to crop the image.
68
+ *
69
+ * Available options:
70
+ * - `center`
71
+ * - `top`
72
+ * - `bottom`
73
+ * - `left`
74
+ * - `right`
75
+ *
76
+ * You can also use `quality` option to change the quality of the image.
77
+ * Be careful about the file size when you change the quality.
78
+ *
79
+ * @default 70
80
+ */
81
+ export const Image = (props: ImageProps) => {
82
+ const {
83
+ src,
84
+ width,
85
+ fill,
86
+ sizes,
87
+ aspectRatio,
88
+ quality = DEFAULT_QUALITY,
89
+ crop = 'center',
90
+ className,
91
+ imageClassName,
92
+ ...restImage
93
+ } = props;
94
+
95
+ const hasGif = typeof src === 'string' && src.includes('.gif');
96
+
97
+ if (fill && !aspectRatio) {
98
+ throw new Error('aspectRatio is required when fill is true');
99
+ }
100
+
101
+ if (fill && !sizes) {
102
+ throw new Error('sizes is required when fill is true');
103
+ }
104
+
105
+ return (
106
+ <div
107
+ className={twMerge('relative inline-block', fill && 'w-full', className)}
108
+ style={{
109
+ ...(fill && { aspectRatio })
110
+ }}
111
+ >
112
+ <NextImage
113
+ {...restImage}
114
+ width={width}
115
+ src={src}
116
+ sizes={sizes}
117
+ fill={fill}
118
+ loader={({ src, width }) => {
119
+ return ImageLoader({
120
+ src,
121
+ width,
122
+ quality: parseInt(String(quality), DEFAULT_QUALITY),
123
+ crop,
124
+ fill,
125
+ aspectRatio
126
+ });
127
+ }}
128
+ className={imageClassName}
129
+ {...(hasGif && { unoptimized: true })}
130
+ />
131
+ </div>
132
+ );
133
+ };
@@ -7,6 +7,7 @@ export * from './input';
7
7
  export * from './lazy-component';
8
8
  export * from './loader-spinner';
9
9
  export * from './mobile-app-toggler';
10
+ export * from './modal';
10
11
  export * from './oauth-login';
11
12
  export * from './plugin-module';
12
13
  export * from './price';
@@ -1,110 +1,110 @@
1
- import clsx from 'clsx';
2
- import { forwardRef, FocusEvent, useState } from 'react';
3
- import { Controller } from 'react-hook-form';
4
- import NumberFormat, { NumberFormatProps } from 'react-number-format';
5
- import { InputProps } from '../types';
6
- import { twMerge } from 'tailwind-merge';
7
-
8
- export const Input = forwardRef<
9
- HTMLInputElement,
10
- InputProps &
11
- Pick<
12
- NumberFormatProps,
13
- 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
- >
15
- >((props, ref) => {
16
- const [focused, setFocused] = useState(false);
17
- const [hasValue, setHasValue] = useState(false);
18
- const {
19
- id,
20
- label,
21
- labelStyle,
22
- error,
23
- mask,
24
- format,
25
- required = false,
26
- ...rest
27
- } = props;
28
- const hasFloatingLabel = label && labelStyle === 'floating';
29
- const inputClass = twMerge(
30
- clsx(
31
- 'text-xs border px-2.5 h-10 placeholder:text-gray-600',
32
- 'focus-visible:outline-none', // disable outline on focus
33
- { 'pt-3': hasFloatingLabel },
34
- error
35
- ? 'border-error focus:border-error'
36
- : 'border-gray-500 hover:border-black focus:border-black'
37
- ),
38
- props.className
39
- );
40
- const inputProps: any = {
41
- id,
42
- ref,
43
- className: inputClass,
44
- onFocus: () => setFocused(true),
45
- onBlur: (event: FocusEvent<HTMLInputElement>) => {
46
- setFocused(false);
47
- setHasValue(!!event.target.value);
48
- }
49
- };
50
-
51
- const Label = () => {
52
- if (!label) return null;
53
-
54
- return (
55
- <label
56
- htmlFor={id}
57
- className={clsx(
58
- 'text-xs text-gray-800',
59
- {
60
- 'absolute left-2.5 pointer-events-none transition-all transform -translate-y-1/2':
61
- hasFloatingLabel
62
- },
63
- { 'mb-2': !hasFloatingLabel },
64
- { 'top-1/3': hasFloatingLabel && (focused || hasValue) },
65
- { 'top-1/2': !(hasFloatingLabel && (focused || hasValue)) }
66
- )}
67
- >
68
- {label} {required && <span className="text-secondary">*</span>}
69
- </label>
70
- );
71
- };
72
-
73
- return (
74
- <div className="flex flex-col">
75
- <div className="relative flex flex-col">
76
- {props.format ? (
77
- <>
78
- {labelStyle !== 'floating' && <Label />}
79
- <Controller
80
- name={props.name ?? ''}
81
- control={props.control}
82
- defaultValue={false}
83
- render={({ field }) => (
84
- <NumberFormat
85
- format={format}
86
- mask={mask ?? ''}
87
- {...rest}
88
- {...field}
89
- {...inputProps}
90
- />
91
- )}
92
- />
93
- {labelStyle === 'floating' && <Label />}
94
- </>
95
- ) : (
96
- <>
97
- {labelStyle !== 'floating' && <Label />}
98
- <input {...rest} {...inputProps} />
99
- {labelStyle === 'floating' && <Label />}
100
- </>
101
- )}
102
- </div>
103
- {error && (
104
- <span className="mt-1 text-sm text-error">{error.message}</span>
105
- )}
106
- </div>
107
- );
108
- });
109
-
110
- Input.displayName = 'Input';
1
+ import clsx from 'clsx';
2
+ import { forwardRef, FocusEvent, useState } from 'react';
3
+ import { Controller } from 'react-hook-form';
4
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
5
+ import { InputProps } from '../types';
6
+ import { twMerge } from 'tailwind-merge';
7
+
8
+ export const Input = forwardRef<
9
+ HTMLInputElement,
10
+ InputProps &
11
+ Pick<
12
+ NumberFormatProps,
13
+ 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
+ >
15
+ >((props, ref) => {
16
+ const [focused, setFocused] = useState(false);
17
+ const [hasValue, setHasValue] = useState(false);
18
+ const {
19
+ id,
20
+ label,
21
+ labelStyle,
22
+ error,
23
+ mask,
24
+ format,
25
+ required = false,
26
+ ...rest
27
+ } = props;
28
+ const hasFloatingLabel = label && labelStyle === 'floating';
29
+ const inputClass = twMerge(
30
+ clsx(
31
+ 'text-xs border px-2.5 h-10 placeholder:text-gray-600',
32
+ 'focus-visible:outline-none', // disable outline on focus
33
+ { 'pt-3': hasFloatingLabel },
34
+ error
35
+ ? 'border-error focus:border-error'
36
+ : 'border-gray-500 hover:border-black focus:border-black'
37
+ ),
38
+ props.className
39
+ );
40
+ const inputProps: any = {
41
+ id,
42
+ ref,
43
+ className: inputClass,
44
+ onFocus: () => setFocused(true),
45
+ onBlur: (event: FocusEvent<HTMLInputElement>) => {
46
+ setFocused(false);
47
+ setHasValue(!!event.target.value);
48
+ }
49
+ };
50
+
51
+ const Label = () => {
52
+ if (!label) return null;
53
+
54
+ return (
55
+ <label
56
+ htmlFor={id}
57
+ className={clsx(
58
+ 'text-xs text-gray-800',
59
+ {
60
+ 'absolute left-2.5 pointer-events-none transition-all transform -translate-y-1/2':
61
+ hasFloatingLabel
62
+ },
63
+ { 'mb-2': !hasFloatingLabel },
64
+ { 'top-1/3': hasFloatingLabel && (focused || hasValue) },
65
+ { 'top-1/2': !(hasFloatingLabel && (focused || hasValue)) }
66
+ )}
67
+ >
68
+ {label} {required && <span className="text-secondary">*</span>}
69
+ </label>
70
+ );
71
+ };
72
+
73
+ return (
74
+ <div className="flex flex-col">
75
+ <div className="relative flex flex-col">
76
+ {props.format ? (
77
+ <>
78
+ {labelStyle !== 'floating' && <Label />}
79
+ <Controller
80
+ name={props.name ?? ''}
81
+ control={props.control}
82
+ defaultValue={false}
83
+ render={({ field }) => (
84
+ <NumberFormat
85
+ format={format}
86
+ mask={mask ?? ''}
87
+ {...rest}
88
+ {...field}
89
+ {...inputProps}
90
+ />
91
+ )}
92
+ />
93
+ {labelStyle === 'floating' && <Label />}
94
+ </>
95
+ ) : (
96
+ <>
97
+ {labelStyle !== 'floating' && <Label />}
98
+ <input {...rest} {...inputProps} />
99
+ {labelStyle === 'floating' && <Label />}
100
+ </>
101
+ )}
102
+ </div>
103
+ {error && (
104
+ <span className="mt-1 text-sm text-error">{error.message}</span>
105
+ )}
106
+ </div>
107
+ );
108
+ });
109
+
110
+ Input.displayName = 'Input';