@tatan22/jcd-product-card 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/components/ProductButtons.d.ts +7 -0
- package/dist/components/ProductCard.d.ts +17 -0
- package/dist/components/ProductContext.d.ts +3 -0
- package/dist/components/ProductImage.d.ts +7 -0
- package/dist/components/ProductTitle.d.ts +7 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/hooks/useProduct.d.ts +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/interfaces/interfaces.d.ts +41 -0
- package/dist/jcd-product-card.cjs.development.js +217 -0
- package/dist/jcd-product-card.cjs.development.js.map +1 -0
- package/dist/jcd-product-card.cjs.production.min.js +2 -0
- package/dist/jcd-product-card.cjs.production.min.js.map +1 -0
- package/dist/jcd-product-card.esm.js +207 -0
- package/dist/jcd-product-card.esm.js.map +1 -0
- package/package.json +95 -0
- package/src/assets/no-image.jpg +0 -0
- package/src/components/ProductButtons.tsx +36 -0
- package/src/components/ProductCard.tsx +70 -0
- package/src/components/ProductContext.tsx +5 -0
- package/src/components/ProductImage.tsx +27 -0
- package/src/components/ProductTitle.tsx +22 -0
- package/src/components/index.ts +16 -0
- package/src/hooks/useProduct.ts +64 -0
- package/src/index.tsx +1 -0
- package/src/interfaces/interfaces.ts +49 -0
- package/src/styles/styles.module.css +71 -0
- package/src/typings.d.ts +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tatancarduar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# JCD-Product-Card
|
|
2
|
+
|
|
3
|
+
Este es un paquete de pruebas de despliegue de NPM
|
|
4
|
+
|
|
5
|
+
## Jhonatan Cardona Duarte
|
|
6
|
+
|
|
7
|
+
## Ejemplos
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { ProductCard , ProductImage, ProductTitle, ProductButtons} from 'jcd-product-card';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<ProductCard
|
|
15
|
+
product={product}
|
|
16
|
+
initialValues={{
|
|
17
|
+
count: 4,
|
|
18
|
+
maxCount: 10,
|
|
19
|
+
}}
|
|
20
|
+
>
|
|
21
|
+
{({ reset, count, increaseBy, isMaxCountReached }) => (
|
|
22
|
+
<>
|
|
23
|
+
<ProductCard.Image />
|
|
24
|
+
<ProductCard.Title />
|
|
25
|
+
<ProductCard.Buttons />
|
|
26
|
+
|
|
27
|
+
</>
|
|
28
|
+
)}
|
|
29
|
+
</ProductCard>
|
|
30
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React, { JSX } from 'react';
|
|
2
|
+
import { InitialValues, onChangeArgs, Product, ProductCardHandlers } from '../interfaces/interfaces';
|
|
3
|
+
export interface Props {
|
|
4
|
+
product: Product;
|
|
5
|
+
children: (args: ProductCardHandlers) => JSX.Element;
|
|
6
|
+
className?: string;
|
|
7
|
+
style?: React.CSSProperties;
|
|
8
|
+
onChange?: (args: onChangeArgs) => void;
|
|
9
|
+
value?: number;
|
|
10
|
+
initialValues?: InitialValues;
|
|
11
|
+
}
|
|
12
|
+
export declare const ProductCard: {
|
|
13
|
+
({ children, product, className, style, onChange, value, initialValues, }: Props): JSX.Element;
|
|
14
|
+
Image: ({ img, className, style }: import("./ProductImage").Props) => JSX.Element;
|
|
15
|
+
Title: ({ title, className, style }: import("./ProductTitle").Props) => React.ReactElement<any, string | ((props: any) => React.ReactElement<any, any> | null) | (new (props: any) => React.Component<any, any, any>)>;
|
|
16
|
+
Buttons: ({ className, style }: import("./ProductButtons").Props) => JSX.Element;
|
|
17
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ProductCardHOCProps } from '../interfaces/interfaces';
|
|
2
|
+
export { ProductButtons } from './ProductButtons';
|
|
3
|
+
export { ProductImage } from './ProductImage';
|
|
4
|
+
export { ProductTitle } from './ProductTitle';
|
|
5
|
+
export declare const ProductCard: ProductCardHOCProps;
|
|
6
|
+
export default ProductCard;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { InitialValues, onChangeArgs, Product } from "../interfaces/interfaces";
|
|
2
|
+
interface useProductArgs {
|
|
3
|
+
product: Product;
|
|
4
|
+
onChange?: (args: onChangeArgs) => void;
|
|
5
|
+
value?: number;
|
|
6
|
+
initialValues?: InitialValues;
|
|
7
|
+
}
|
|
8
|
+
export declare const useProduct: ({ onChange, product, value, initialValues, }: useProductArgs) => {
|
|
9
|
+
counter: number;
|
|
10
|
+
maxCount: number | undefined;
|
|
11
|
+
increaseBy: (value?: number | undefined) => void;
|
|
12
|
+
isMaxCountReached: boolean;
|
|
13
|
+
reset: () => void;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { JSX, JSXElementConstructor, ReactElement } from 'react';
|
|
2
|
+
import { Props as ProductCardProps } from '../components/ProductCard';
|
|
3
|
+
import { Props as ProductTitleProps } from '../components/ProductTitle';
|
|
4
|
+
import { Props as ProductImageProps } from '../components/ProductImage';
|
|
5
|
+
import { Props as ProductButtonsProps } from '../components/ProductButtons';
|
|
6
|
+
export interface Product {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
img?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ProductContextProps {
|
|
12
|
+
counter: number;
|
|
13
|
+
maxCount?: number;
|
|
14
|
+
product: Product;
|
|
15
|
+
increaseBy: (value?: number) => void;
|
|
16
|
+
}
|
|
17
|
+
export interface ProductCardHOCProps {
|
|
18
|
+
({ children, product }: ProductCardProps): JSX.Element;
|
|
19
|
+
Image: (Props: ProductImageProps) => JSX.Element;
|
|
20
|
+
Button: (Props: ProductButtonsProps) => JSX.Element;
|
|
21
|
+
Title: (Props: ProductTitleProps) => ReactElement<unknown, string | JSXElementConstructor<any>>;
|
|
22
|
+
}
|
|
23
|
+
export interface onChangeArgs {
|
|
24
|
+
product: Product;
|
|
25
|
+
count: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ProductsInCart extends Product {
|
|
28
|
+
count: number;
|
|
29
|
+
}
|
|
30
|
+
export interface InitialValues {
|
|
31
|
+
count?: number;
|
|
32
|
+
maxCount?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ProductCardHandlers {
|
|
35
|
+
count: number;
|
|
36
|
+
isMaxCountReached: boolean;
|
|
37
|
+
maxCount?: number;
|
|
38
|
+
product: Product;
|
|
39
|
+
increaseBy: (value: number) => void;
|
|
40
|
+
reset: () => void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
|
+
|
|
7
|
+
var React = require('react');
|
|
8
|
+
var React__default = _interopDefault(React);
|
|
9
|
+
|
|
10
|
+
var useProduct = function useProduct(_ref) {
|
|
11
|
+
var onChange = _ref.onChange,
|
|
12
|
+
product = _ref.product,
|
|
13
|
+
_ref$value = _ref.value,
|
|
14
|
+
value = _ref$value === void 0 ? 0 : _ref$value,
|
|
15
|
+
initialValues = _ref.initialValues;
|
|
16
|
+
// if (initialValues) {
|
|
17
|
+
// value = initialValues.count || value;
|
|
18
|
+
// }
|
|
19
|
+
var _useState = React.useState((initialValues == null ? void 0 : initialValues.count) || value),
|
|
20
|
+
counter = _useState[0],
|
|
21
|
+
setCounter = _useState[1];
|
|
22
|
+
var isMounted = React.useRef(false);
|
|
23
|
+
var increaseBy = function increaseBy(value) {
|
|
24
|
+
var amount = value != null ? value : 1;
|
|
25
|
+
var newValue = Math.max(counter + amount, 0);
|
|
26
|
+
if (initialValues != null && initialValues.maxCount) {
|
|
27
|
+
newValue = Math.min(newValue, initialValues.maxCount);
|
|
28
|
+
}
|
|
29
|
+
setCounter(newValue);
|
|
30
|
+
onChange && onChange({
|
|
31
|
+
count: newValue,
|
|
32
|
+
product: product
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
var reset = function reset() {
|
|
36
|
+
var newValue = (initialValues == null ? void 0 : initialValues.count) || value;
|
|
37
|
+
setCounter(newValue);
|
|
38
|
+
onChange && onChange({
|
|
39
|
+
count: newValue,
|
|
40
|
+
product: product
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
// El use ref se puede usar como un elemento que no tiene dependencias de renderizado
|
|
44
|
+
React.useEffect(function () {
|
|
45
|
+
if (!isMounted.current) return;
|
|
46
|
+
setCounter(value);
|
|
47
|
+
}, [value]);
|
|
48
|
+
React.useEffect(function () {
|
|
49
|
+
isMounted.current = true;
|
|
50
|
+
}, []);
|
|
51
|
+
return {
|
|
52
|
+
//Props
|
|
53
|
+
counter: counter,
|
|
54
|
+
maxCount: initialValues == null ? void 0 : initialValues.maxCount,
|
|
55
|
+
//Methods
|
|
56
|
+
increaseBy: increaseBy,
|
|
57
|
+
isMaxCountReached: !!(initialValues != null && initialValues.maxCount) && counter === initialValues.maxCount,
|
|
58
|
+
reset: reset
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function styleInject(css, ref) {
|
|
63
|
+
if ( ref === void 0 ) ref = {};
|
|
64
|
+
var insertAt = ref.insertAt;
|
|
65
|
+
|
|
66
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
67
|
+
|
|
68
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
69
|
+
var style = document.createElement('style');
|
|
70
|
+
style.type = 'text/css';
|
|
71
|
+
|
|
72
|
+
if (insertAt === 'top') {
|
|
73
|
+
if (head.firstChild) {
|
|
74
|
+
head.insertBefore(style, head.firstChild);
|
|
75
|
+
} else {
|
|
76
|
+
head.appendChild(style);
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
head.appendChild(style);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (style.styleSheet) {
|
|
83
|
+
style.styleSheet.cssText = css;
|
|
84
|
+
} else {
|
|
85
|
+
style.appendChild(document.createTextNode(css));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
var css_248z = ".styles-module_productCard__oaIVo {\n background-color: #1e2025;\n border-radius: 15px;\n box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.15);\n color: white;\n padding-bottom: 5px;\n font-family: Arial, Helvetica, sans-serif;\n width: 250px;\n margin-right: 5px;\n margin-top: 5px;\n}\n\n.styles-module_productImg__vPsTp {\n border-radius: 15px 15px 0px 0px;\n width: 100%;\n}\n\n.styles-module_productDescription__Ariub {\n margin: 10px;\n}\n\n.styles-module_buttonsContainer__ghCDF {\n margin: 10px;\n display: flex;\n flex-direction: row;\n}\n\n.styles-module_buttonMinus__BTgTf {\n cursor: pointer;\n background-color: transparent;\n border: 1px solid white;\n border-radius: 5px 0px 0px 5px;\n color: white;\n font-size: 20px;\n width: 30px;\n}\n\n.styles-module_buttonMinus__BTgTf:hover {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.styles-module_countLabel__S6HZ- {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n color: white;\n font-size: 16px;\n height: 25px;\n padding-top: 5px;\n text-align: center;\n width: 30px;\n}\n\n.styles-module_buttonAdd__s8wd6 {\n cursor: pointer;\n background-color: transparent;\n border: 1px solid white;\n border-radius: 0px 5px 5px 0px;\n color: white;\n font-size: 20px;\n width: 30px;\n}\n\n.styles-module_buttonAdd__s8wd6:hover {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.styles-module_disabled__k5aZm {\n border-color: grey !important;\n border-left: 1px solid white !important;\n color: grey !important;\n}\n";
|
|
90
|
+
var styles = {"productCard":"styles-module_productCard__oaIVo","productImg":"styles-module_productImg__vPsTp","productDescription":"styles-module_productDescription__Ariub","buttonsContainer":"styles-module_buttonsContainer__ghCDF","buttonMinus":"styles-module_buttonMinus__BTgTf","countLabel":"styles-module_countLabel__S6HZ-","buttonAdd":"styles-module_buttonAdd__s8wd6","disabled":"styles-module_disabled__k5aZm"};
|
|
91
|
+
styleInject(css_248z);
|
|
92
|
+
|
|
93
|
+
// ProductContext.tsx
|
|
94
|
+
var ProductContext = /*#__PURE__*/React.createContext({});
|
|
95
|
+
|
|
96
|
+
var DEFAULT_IMAGE = "https://via.placeholder.com/300x200?text=No+Image";
|
|
97
|
+
var ProductImage = function ProductImage(_ref) {
|
|
98
|
+
var img = _ref.img,
|
|
99
|
+
className = _ref.className,
|
|
100
|
+
style = _ref.style;
|
|
101
|
+
var _useContext = React.useContext(ProductContext),
|
|
102
|
+
product = _useContext.product;
|
|
103
|
+
var imgToShow = "";
|
|
104
|
+
if (img) {
|
|
105
|
+
imgToShow = img;
|
|
106
|
+
} else if (product.img) {
|
|
107
|
+
imgToShow = product.img;
|
|
108
|
+
} else {
|
|
109
|
+
imgToShow = DEFAULT_IMAGE;
|
|
110
|
+
}
|
|
111
|
+
return React__default.createElement("img", {
|
|
112
|
+
className: "\t" + styles.productImg + " " + className,
|
|
113
|
+
src: imgToShow,
|
|
114
|
+
alt: "Product",
|
|
115
|
+
style: style
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// export const ProductTitle = ({ title, className }: { title?: string, className?: string }): ReactElement => {
|
|
120
|
+
var ProductTitle = function ProductTitle(_ref) {
|
|
121
|
+
var title = _ref.title,
|
|
122
|
+
className = _ref.className,
|
|
123
|
+
style = _ref.style;
|
|
124
|
+
var _useContext = React.useContext(ProductContext),
|
|
125
|
+
product = _useContext.product;
|
|
126
|
+
return React__default.createElement("span", {
|
|
127
|
+
className: styles.productTitle + " " + className,
|
|
128
|
+
style: style
|
|
129
|
+
}, title || product.title);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
var ProductButtons = function ProductButtons(_ref) {
|
|
133
|
+
var className = _ref.className,
|
|
134
|
+
style = _ref.style;
|
|
135
|
+
var _useContext = React.useContext(ProductContext),
|
|
136
|
+
increaseBy = _useContext.increaseBy,
|
|
137
|
+
counter = _useContext.counter,
|
|
138
|
+
maxCount = _useContext.maxCount;
|
|
139
|
+
//TODO: Una función isMaxReached = useCallback, dependencias [counter, maxCounter]
|
|
140
|
+
//? True si el count === maxCount, caso contrario False
|
|
141
|
+
var isMaxReached = React.useCallback(function () {
|
|
142
|
+
return !!maxCount && counter === maxCount;
|
|
143
|
+
},
|
|
144
|
+
// retorna true o false
|
|
145
|
+
[counter, maxCount]);
|
|
146
|
+
return React__default.createElement("div", {
|
|
147
|
+
className: "\t" + styles.buttonsContainer + " " + className,
|
|
148
|
+
style: style
|
|
149
|
+
}, React__default.createElement("button", {
|
|
150
|
+
className: styles.buttonMinus,
|
|
151
|
+
onClick: function onClick() {
|
|
152
|
+
return increaseBy(-1);
|
|
153
|
+
}
|
|
154
|
+
}, "-"), React__default.createElement("div", {
|
|
155
|
+
className: styles.countLabel
|
|
156
|
+
}, counter), React__default.createElement("button", {
|
|
157
|
+
className: styles.buttonAdd + " " + (isMaxReached() && styles.disabled),
|
|
158
|
+
onClick: function onClick() {
|
|
159
|
+
return increaseBy(1);
|
|
160
|
+
}
|
|
161
|
+
}, "+"));
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
var Provider = ProductContext.Provider;
|
|
165
|
+
var ProductCard = function ProductCard(_ref) {
|
|
166
|
+
var children = _ref.children,
|
|
167
|
+
product = _ref.product,
|
|
168
|
+
className = _ref.className,
|
|
169
|
+
style = _ref.style,
|
|
170
|
+
onChange = _ref.onChange,
|
|
171
|
+
value = _ref.value,
|
|
172
|
+
initialValues = _ref.initialValues;
|
|
173
|
+
var _useProduct = useProduct({
|
|
174
|
+
onChange: onChange,
|
|
175
|
+
product: product,
|
|
176
|
+
value: value,
|
|
177
|
+
initialValues: initialValues
|
|
178
|
+
}),
|
|
179
|
+
counter = _useProduct.counter,
|
|
180
|
+
increaseBy = _useProduct.increaseBy,
|
|
181
|
+
isMaxCountReached = _useProduct.isMaxCountReached,
|
|
182
|
+
maxCount = _useProduct.maxCount,
|
|
183
|
+
reset = _useProduct.reset;
|
|
184
|
+
return React__default.createElement(Provider, {
|
|
185
|
+
value: {
|
|
186
|
+
counter: counter,
|
|
187
|
+
increaseBy: increaseBy,
|
|
188
|
+
maxCount: maxCount,
|
|
189
|
+
product: product
|
|
190
|
+
}
|
|
191
|
+
}, React__default.createElement("div", {
|
|
192
|
+
className: styles.productCard + " " + className,
|
|
193
|
+
style: style
|
|
194
|
+
}, children({
|
|
195
|
+
count: counter,
|
|
196
|
+
isMaxCountReached: isMaxCountReached,
|
|
197
|
+
maxCount: initialValues == null ? void 0 : initialValues.maxCount,
|
|
198
|
+
product: product,
|
|
199
|
+
increaseBy: increaseBy,
|
|
200
|
+
reset: reset
|
|
201
|
+
})));
|
|
202
|
+
};
|
|
203
|
+
ProductCard.Image = ProductImage;
|
|
204
|
+
ProductCard.Title = ProductTitle;
|
|
205
|
+
ProductCard.Buttons = ProductButtons;
|
|
206
|
+
|
|
207
|
+
var ProductCard$1 = /*#__PURE__*/Object.assign(ProductCard, {
|
|
208
|
+
Button: ProductButtons,
|
|
209
|
+
Image: ProductImage,
|
|
210
|
+
Title: ProductTitle
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
exports.ProductButtons = ProductButtons;
|
|
214
|
+
exports.ProductCard = ProductCard$1;
|
|
215
|
+
exports.ProductImage = ProductImage;
|
|
216
|
+
exports.ProductTitle = ProductTitle;
|
|
217
|
+
//# sourceMappingURL=jcd-product-card.cjs.development.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcd-product-card.cjs.development.js","sources":["../src/hooks/useProduct.ts","../node_modules/style-inject/dist/style-inject.es.js","../src/components/ProductContext.tsx","../src/components/ProductImage.tsx","../src/components/ProductTitle.tsx","../src/components/ProductButtons.tsx","../src/components/ProductCard.tsx","../src/components/index.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\r\nimport { InitialValues, onChangeArgs, Product } from \"../interfaces/interfaces\";\r\n\r\ninterface useProductArgs {\r\n\tproduct: Product;\r\n\tonChange?: (args: onChangeArgs) => void;\r\n\tvalue?: number;\r\n\tinitialValues?: InitialValues;\r\n}\r\n\r\nexport const useProduct = ({\r\n\tonChange,\r\n\tproduct,\r\n\tvalue = 0,\r\n\tinitialValues,\r\n}: useProductArgs) => {\r\n\t// if (initialValues) {\r\n\t// \tvalue = initialValues.count || value;\r\n\t// }\r\n\r\n\tconst [counter, setCounter] = useState<number>(initialValues?.count || value);\r\n\r\n\tconst isMounted = useRef(false);\r\n\r\n\tconst increaseBy = (value?: number) => {\r\n\t\tconst amount = value ?? 1;\r\n\t\tlet newValue = Math.max(counter + amount, 0);\r\n\r\n\t\tif (initialValues?.maxCount) {\r\n\t\t\tnewValue = Math.min(newValue, initialValues.maxCount);\r\n\t\t}\r\n\r\n\t\tsetCounter(newValue);\r\n\r\n\t\tonChange && onChange({ count: newValue, product });\r\n\t};\r\n\r\n\tconst reset = () => {\r\n\t\tconst newValue = initialValues?.count || value;\r\n\t\tsetCounter(newValue);\r\n\t\tonChange && onChange({ count: newValue, product });\r\n\r\n\t}\r\n\r\n\t// El use ref se puede usar como un elemento que no tiene dependencias de renderizado\r\n\tuseEffect(() => {\r\n\t\tif (!isMounted.current) return;\r\n\t\tsetCounter(value);\r\n\t}, [value]);\r\n\r\n\tuseEffect(() => {\r\n\t\tisMounted.current = true;\r\n\t}, []);\r\n\r\n\treturn {\r\n\t\t//Props\r\n\t\tcounter,\r\n\t\tmaxCount: initialValues?.maxCount,\r\n\t\t//Methods\r\n\t\tincreaseBy,\r\n\t\tisMaxCountReached: !!initialValues?.maxCount && counter === initialValues.maxCount,\r\n\t\treset\r\n\t};\r\n};\r\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","// ProductContext.tsx\r\nimport { createContext } from \"react\";\r\nimport { ProductContextProps } from \"../interfaces/interfaces\";\r\n\r\nexport const ProductContext = createContext({} as ProductContextProps);","import React, { useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\n\r\n// import noImages from \"../assets/no-image.jpg\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\timg?: string;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\nconst DEFAULT_IMAGE =\r\n \"https://via.placeholder.com/300x200?text=No+Image\";\r\n\r\nexport const ProductImage = ({ img , className, style }: Props) => {\r\n\tconst { product } = useContext(ProductContext);\r\n\tlet imgToShow: string = \"\";\r\n\tif (img) {\r\n\t\timgToShow = img;\r\n\t} else if (product.img) {\r\n\t\timgToShow = product.img;\r\n\t} else {\r\n\t\timgToShow = DEFAULT_IMAGE;\r\n\t}\r\n\r\n\treturn <img className={`\t${styles.productImg} ${className}`} src={imgToShow} alt=\"Product\" style={style} />;\r\n};\r\n","import React, { ReactElement, useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\ttitle?: string;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\n// export const ProductTitle = ({ title, className }: { title?: string, className?: string }): ReactElement => {\r\nexport const ProductTitle = ({ title, className, style }: Props): ReactElement => {\r\n\tconst { product } = useContext(ProductContext);\r\n\r\n\treturn (\r\n\t\t<span className={`${styles.productTitle} ${className}`} style={style}>\r\n\t\t\t{title || product.title}\r\n\t\t</span>\r\n\t);\r\n};\r\n\r\n\r\n","import React, { useCallback, useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\t// className para poder recibir estilos personalizados\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n\tactiveBtnClass?: string;\r\n}\r\n\r\nexport const ProductButtons = ({ className, style }: Props) => {\r\n\r\n\tconst { increaseBy, counter, maxCount } = useContext(ProductContext);\r\n\r\n//TODO: Una función isMaxReached = useCallback, dependencias [counter, maxCounter]\r\n//? True si el count === maxCount, caso contrario False\r\n\r\nconst isMaxReached = useCallback(\r\n\t() => !!maxCount && counter === maxCount, // retorna true o false\r\n\t[counter, maxCount],\r\n)\r\n\r\n\treturn (\r\n\t\t<div className={`\t${styles.buttonsContainer} ${className}`} style={style}>\r\n\t\t\t<button className={styles.buttonMinus} onClick={() => increaseBy(-1)}>\r\n\t\t\t\t-\r\n\t\t\t</button>\r\n\t\t\t<div className={styles.countLabel}>{counter}</div>\r\n\r\n\t\t\t<button className={`${styles.buttonAdd} ${ isMaxReached() && styles.disabled}`} onClick={() => increaseBy(1)}>\r\n\t\t\t\t+\r\n\t\t\t</button>\r\n\t\t</div>\r\n\t);\r\n};\r\n","import React, { JSX } from 'react';\r\nimport { useProduct } from '../hooks/useProduct';\r\nimport {\r\n InitialValues,\r\n onChangeArgs,\r\n Product,\r\n ProductCardHandlers,\r\n} from '../interfaces/interfaces';\r\nimport styles from '../styles/styles.module.css';\r\n\r\nimport { ProductImage } from './ProductImage';\r\nimport { ProductTitle } from './ProductTitle';\r\nimport { ProductButtons } from './ProductButtons';\r\nimport { ProductContext } from './ProductContext';\r\n\r\nconst { Provider } = ProductContext;\r\n\r\nexport interface Props {\r\n product: Product;\r\n // children?: ReactElement | ReactElement[];\r\n children: (args: ProductCardHandlers) => JSX.Element;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n onChange?: (args: onChangeArgs) => void;\r\n value?: number;\r\n initialValues?: InitialValues;\r\n}\r\n\r\nexport const ProductCard = ({\r\n children,\r\n product,\r\n className,\r\n style,\r\n onChange,\r\n value,\r\n initialValues,\r\n}: Props) => {\r\n const {\r\n counter,\r\n increaseBy,\r\n isMaxCountReached,\r\n maxCount,\r\n reset,\r\n } = useProduct({\r\n onChange,\r\n product,\r\n value,\r\n initialValues,\r\n });\r\n\r\n return (\r\n <Provider value={{ counter, increaseBy, maxCount, product }}>\r\n <div className={`${styles.productCard} ${className}`} style={style}>\r\n {/* {children} */}\r\n {children({\r\n count: counter,\r\n isMaxCountReached,\r\n maxCount: initialValues?.maxCount,\r\n product,\r\n increaseBy,\r\n reset,\r\n })}\r\n </div>\r\n </Provider>\r\n );\r\n};\r\n\r\nProductCard.Image = ProductImage;\r\nProductCard.Title = ProductTitle;\r\nProductCard.Buttons = ProductButtons;\r\n","import { ProductCard as ProductCardHOC } from './ProductCard';\r\nimport { ProductCardHOCProps } from '../interfaces/interfaces';\r\nimport { ProductButtons } from './ProductButtons';\r\nimport { ProductImage } from './ProductImage';\r\nimport { ProductTitle } from './ProductTitle';\r\nexport { ProductButtons } from './ProductButtons';\r\nexport { ProductImage } from './ProductImage';\r\nexport { ProductTitle } from './ProductTitle';\r\n\r\nexport const ProductCard: ProductCardHOCProps = Object.assign(ProductCardHOC, {\r\n Button: ProductButtons,\r\n Image: ProductImage,\r\n Title: ProductTitle,\r\n});\r\n\r\nexport default ProductCard;"],"names":["useProduct","_ref","onChange","product","_ref$value","value","initialValues","_useState","useState","count","counter","setCounter","isMounted","useRef","increaseBy","amount","newValue","Math","max","maxCount","min","reset","useEffect","current","isMaxCountReached","ProductContext","createContext","DEFAULT_IMAGE","ProductImage","img","className","style","_useContext","useContext","imgToShow","React","styles","productImg","src","alt","ProductTitle","title","productTitle","ProductButtons","isMaxReached","useCallback","buttonsContainer","buttonMinus","onClick","countLabel","buttonAdd","disabled","Provider","ProductCard","children","_useProduct","productCard","Image","Title","Buttons","Object","assign","ProductCardHOC","Button"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t,e=require("react"),n=(t=e)&&"object"==typeof t&&"default"in t?t.default:t,o={productCard:"styles-module_productCard__oaIVo",productImg:"styles-module_productImg__vPsTp",productDescription:"styles-module_productDescription__Ariub",buttonsContainer:"styles-module_buttonsContainer__ghCDF",buttonMinus:"styles-module_buttonMinus__BTgTf",countLabel:"styles-module_countLabel__S6HZ-",buttonAdd:"styles-module_buttonAdd__s8wd6",disabled:"styles-module_disabled__k5aZm"};!function(t,e){void 0===e&&(e={});var n=e.insertAt;if("undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css","top"===n&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=t:r.appendChild(document.createTextNode(t))}}(".styles-module_productCard__oaIVo {\n background-color: #1e2025;\n border-radius: 15px;\n box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.15);\n color: white;\n padding-bottom: 5px;\n font-family: Arial, Helvetica, sans-serif;\n width: 250px;\n margin-right: 5px;\n margin-top: 5px;\n}\n\n.styles-module_productImg__vPsTp {\n border-radius: 15px 15px 0px 0px;\n width: 100%;\n}\n\n.styles-module_productDescription__Ariub {\n margin: 10px;\n}\n\n.styles-module_buttonsContainer__ghCDF {\n margin: 10px;\n display: flex;\n flex-direction: row;\n}\n\n.styles-module_buttonMinus__BTgTf {\n cursor: pointer;\n background-color: transparent;\n border: 1px solid white;\n border-radius: 5px 0px 0px 5px;\n color: white;\n font-size: 20px;\n width: 30px;\n}\n\n.styles-module_buttonMinus__BTgTf:hover {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.styles-module_countLabel__S6HZ- {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n color: white;\n font-size: 16px;\n height: 25px;\n padding-top: 5px;\n text-align: center;\n width: 30px;\n}\n\n.styles-module_buttonAdd__s8wd6 {\n cursor: pointer;\n background-color: transparent;\n border: 1px solid white;\n border-radius: 0px 5px 5px 0px;\n color: white;\n font-size: 20px;\n width: 30px;\n}\n\n.styles-module_buttonAdd__s8wd6:hover {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.styles-module_disabled__k5aZm {\n border-color: grey !important;\n border-left: 1px solid white !important;\n color: grey !important;\n}\n");var r=e.createContext({}),u=function(t){var u=t.img,a=t.className,s=t.style,l=e.useContext(r).product;return n.createElement("img",{className:"\t"+o.productImg+" "+a,src:u||(l.img?l.img:"https://via.placeholder.com/300x200?text=No+Image"),alt:"Product",style:s})},a=function(t){var u=t.title,a=t.className,s=t.style,l=e.useContext(r);return n.createElement("span",{className:o.productTitle+" "+a,style:s},u||l.product.title)},s=function(t){var u=t.className,a=t.style,s=e.useContext(r),l=s.increaseBy,d=s.counter,i=s.maxCount,c=e.useCallback((function(){return!!i&&d===i}),[d,i]);return n.createElement("div",{className:"\t"+o.buttonsContainer+" "+u,style:a},n.createElement("button",{className:o.buttonMinus,onClick:function(){return l(-1)}},"-"),n.createElement("div",{className:o.countLabel},d),n.createElement("button",{className:o.buttonAdd+" "+(c()&&o.disabled),onClick:function(){return l(1)}},"+"))},l=r.Provider,d=function(t){var r=t.children,u=t.product,a=t.className,s=t.style,d=t.initialValues,i=function(t){var n=t.onChange,o=t.product,r=t.value,u=void 0===r?0:r,a=t.initialValues,s=e.useState((null==a?void 0:a.count)||u),l=s[0],d=s[1],i=e.useRef(!1);return e.useEffect((function(){i.current&&d(u)}),[u]),e.useEffect((function(){i.current=!0}),[]),{counter:l,maxCount:null==a?void 0:a.maxCount,increaseBy:function(t){var e=Math.max(l+(null!=t?t:1),0);null!=a&&a.maxCount&&(e=Math.min(e,a.maxCount)),d(e),n&&n({count:e,product:o})},isMaxCountReached:!(null==a||!a.maxCount)&&l===a.maxCount,reset:function(){var t=(null==a?void 0:a.count)||u;d(t),n&&n({count:t,product:o})}}}({onChange:t.onChange,product:u,value:t.value,initialValues:d}),c=i.counter,p=i.increaseBy;return n.createElement(l,{value:{counter:c,increaseBy:p,maxCount:i.maxCount,product:u}},n.createElement("div",{className:o.productCard+" "+a,style:s},r({count:c,isMaxCountReached:i.isMaxCountReached,maxCount:null==d?void 0:d.maxCount,product:u,increaseBy:p,reset:i.reset})))};d.Image=u,d.Title=a,d.Buttons=s;var i=Object.assign(d,{Button:s,Image:u,Title:a});exports.ProductButtons=s,exports.ProductCard=i,exports.ProductImage=u,exports.ProductTitle=a;
|
|
2
|
+
//# sourceMappingURL=jcd-product-card.cjs.production.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcd-product-card.cjs.production.min.js","sources":["../node_modules/style-inject/dist/style-inject.es.js","../src/components/ProductContext.tsx","../src/components/ProductImage.tsx","../src/components/ProductTitle.tsx","../src/components/ProductButtons.tsx","../src/components/ProductCard.tsx","../src/hooks/useProduct.ts","../src/components/index.ts"],"sourcesContent":["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","// ProductContext.tsx\r\nimport { createContext } from \"react\";\r\nimport { ProductContextProps } from \"../interfaces/interfaces\";\r\n\r\nexport const ProductContext = createContext({} as ProductContextProps);","import React, { useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\n\r\n// import noImages from \"../assets/no-image.jpg\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\timg?: string;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\nconst DEFAULT_IMAGE =\r\n \"https://via.placeholder.com/300x200?text=No+Image\";\r\n\r\nexport const ProductImage = ({ img , className, style }: Props) => {\r\n\tconst { product } = useContext(ProductContext);\r\n\tlet imgToShow: string = \"\";\r\n\tif (img) {\r\n\t\timgToShow = img;\r\n\t} else if (product.img) {\r\n\t\timgToShow = product.img;\r\n\t} else {\r\n\t\timgToShow = DEFAULT_IMAGE;\r\n\t}\r\n\r\n\treturn <img className={`\t${styles.productImg} ${className}`} src={imgToShow} alt=\"Product\" style={style} />;\r\n};\r\n","import React, { ReactElement, useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\ttitle?: string;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\n// export const ProductTitle = ({ title, className }: { title?: string, className?: string }): ReactElement => {\r\nexport const ProductTitle = ({ title, className, style }: Props): ReactElement => {\r\n\tconst { product } = useContext(ProductContext);\r\n\r\n\treturn (\r\n\t\t<span className={`${styles.productTitle} ${className}`} style={style}>\r\n\t\t\t{title || product.title}\r\n\t\t</span>\r\n\t);\r\n};\r\n\r\n\r\n","import React, { useCallback, useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\t// className para poder recibir estilos personalizados\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n\tactiveBtnClass?: string;\r\n}\r\n\r\nexport const ProductButtons = ({ className, style }: Props) => {\r\n\r\n\tconst { increaseBy, counter, maxCount } = useContext(ProductContext);\r\n\r\n//TODO: Una función isMaxReached = useCallback, dependencias [counter, maxCounter]\r\n//? True si el count === maxCount, caso contrario False\r\n\r\nconst isMaxReached = useCallback(\r\n\t() => !!maxCount && counter === maxCount, // retorna true o false\r\n\t[counter, maxCount],\r\n)\r\n\r\n\treturn (\r\n\t\t<div className={`\t${styles.buttonsContainer} ${className}`} style={style}>\r\n\t\t\t<button className={styles.buttonMinus} onClick={() => increaseBy(-1)}>\r\n\t\t\t\t-\r\n\t\t\t</button>\r\n\t\t\t<div className={styles.countLabel}>{counter}</div>\r\n\r\n\t\t\t<button className={`${styles.buttonAdd} ${ isMaxReached() && styles.disabled}`} onClick={() => increaseBy(1)}>\r\n\t\t\t\t+\r\n\t\t\t</button>\r\n\t\t</div>\r\n\t);\r\n};\r\n","import React, { JSX } from 'react';\r\nimport { useProduct } from '../hooks/useProduct';\r\nimport {\r\n InitialValues,\r\n onChangeArgs,\r\n Product,\r\n ProductCardHandlers,\r\n} from '../interfaces/interfaces';\r\nimport styles from '../styles/styles.module.css';\r\n\r\nimport { ProductImage } from './ProductImage';\r\nimport { ProductTitle } from './ProductTitle';\r\nimport { ProductButtons } from './ProductButtons';\r\nimport { ProductContext } from './ProductContext';\r\n\r\nconst { Provider } = ProductContext;\r\n\r\nexport interface Props {\r\n product: Product;\r\n // children?: ReactElement | ReactElement[];\r\n children: (args: ProductCardHandlers) => JSX.Element;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n onChange?: (args: onChangeArgs) => void;\r\n value?: number;\r\n initialValues?: InitialValues;\r\n}\r\n\r\nexport const ProductCard = ({\r\n children,\r\n product,\r\n className,\r\n style,\r\n onChange,\r\n value,\r\n initialValues,\r\n}: Props) => {\r\n const {\r\n counter,\r\n increaseBy,\r\n isMaxCountReached,\r\n maxCount,\r\n reset,\r\n } = useProduct({\r\n onChange,\r\n product,\r\n value,\r\n initialValues,\r\n });\r\n\r\n return (\r\n <Provider value={{ counter, increaseBy, maxCount, product }}>\r\n <div className={`${styles.productCard} ${className}`} style={style}>\r\n {/* {children} */}\r\n {children({\r\n count: counter,\r\n isMaxCountReached,\r\n maxCount: initialValues?.maxCount,\r\n product,\r\n increaseBy,\r\n reset,\r\n })}\r\n </div>\r\n </Provider>\r\n );\r\n};\r\n\r\nProductCard.Image = ProductImage;\r\nProductCard.Title = ProductTitle;\r\nProductCard.Buttons = ProductButtons;\r\n","import { useEffect, useRef, useState } from \"react\";\r\nimport { InitialValues, onChangeArgs, Product } from \"../interfaces/interfaces\";\r\n\r\ninterface useProductArgs {\r\n\tproduct: Product;\r\n\tonChange?: (args: onChangeArgs) => void;\r\n\tvalue?: number;\r\n\tinitialValues?: InitialValues;\r\n}\r\n\r\nexport const useProduct = ({\r\n\tonChange,\r\n\tproduct,\r\n\tvalue = 0,\r\n\tinitialValues,\r\n}: useProductArgs) => {\r\n\t// if (initialValues) {\r\n\t// \tvalue = initialValues.count || value;\r\n\t// }\r\n\r\n\tconst [counter, setCounter] = useState<number>(initialValues?.count || value);\r\n\r\n\tconst isMounted = useRef(false);\r\n\r\n\tconst increaseBy = (value?: number) => {\r\n\t\tconst amount = value ?? 1;\r\n\t\tlet newValue = Math.max(counter + amount, 0);\r\n\r\n\t\tif (initialValues?.maxCount) {\r\n\t\t\tnewValue = Math.min(newValue, initialValues.maxCount);\r\n\t\t}\r\n\r\n\t\tsetCounter(newValue);\r\n\r\n\t\tonChange && onChange({ count: newValue, product });\r\n\t};\r\n\r\n\tconst reset = () => {\r\n\t\tconst newValue = initialValues?.count || value;\r\n\t\tsetCounter(newValue);\r\n\t\tonChange && onChange({ count: newValue, product });\r\n\r\n\t}\r\n\r\n\t// El use ref se puede usar como un elemento que no tiene dependencias de renderizado\r\n\tuseEffect(() => {\r\n\t\tif (!isMounted.current) return;\r\n\t\tsetCounter(value);\r\n\t}, [value]);\r\n\r\n\tuseEffect(() => {\r\n\t\tisMounted.current = true;\r\n\t}, []);\r\n\r\n\treturn {\r\n\t\t//Props\r\n\t\tcounter,\r\n\t\tmaxCount: initialValues?.maxCount,\r\n\t\t//Methods\r\n\t\tincreaseBy,\r\n\t\tisMaxCountReached: !!initialValues?.maxCount && counter === initialValues.maxCount,\r\n\t\treset\r\n\t};\r\n};\r\n","import { ProductCard as ProductCardHOC } from './ProductCard';\r\nimport { ProductCardHOCProps } from '../interfaces/interfaces';\r\nimport { ProductButtons } from './ProductButtons';\r\nimport { ProductImage } from './ProductImage';\r\nimport { ProductTitle } from './ProductTitle';\r\nexport { ProductButtons } from './ProductButtons';\r\nexport { ProductImage } from './ProductImage';\r\nexport { ProductTitle } from './ProductTitle';\r\n\r\nexport const ProductCard: ProductCardHOCProps = Object.assign(ProductCardHOC, {\r\n Button: ProductButtons,\r\n Image: ProductImage,\r\n Title: ProductTitle,\r\n});\r\n\r\nexport default ProductCard;"],"names":["css","ref","insertAt","document","head","getElementsByTagName","style","createElement","type","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","ProductContext","createContext","ProductImage","_ref","img","className","product","useContext","React","styles","productImg","src","alt","ProductTitle","title","_useContext","productTitle","ProductButtons","increaseBy","counter","maxCount","isMaxReached","useCallback","buttonsContainer","buttonMinus","onClick","countLabel","buttonAdd","disabled","Provider","ProductCard","children","initialValues","_useProduct","onChange","_ref$value","value","_useState","useState","count","setCounter","isMounted","useRef","useEffect","current","newValue","Math","max","min","isMaxCountReached","reset","useProduct","productCard","Image","Title","Buttons","Object","assign","ProductCardHOC","Button"],"mappings":"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"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect, createContext, useContext, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
var useProduct = function useProduct(_ref) {
|
|
4
|
+
var onChange = _ref.onChange,
|
|
5
|
+
product = _ref.product,
|
|
6
|
+
_ref$value = _ref.value,
|
|
7
|
+
value = _ref$value === void 0 ? 0 : _ref$value,
|
|
8
|
+
initialValues = _ref.initialValues;
|
|
9
|
+
// if (initialValues) {
|
|
10
|
+
// value = initialValues.count || value;
|
|
11
|
+
// }
|
|
12
|
+
var _useState = useState((initialValues == null ? void 0 : initialValues.count) || value),
|
|
13
|
+
counter = _useState[0],
|
|
14
|
+
setCounter = _useState[1];
|
|
15
|
+
var isMounted = useRef(false);
|
|
16
|
+
var increaseBy = function increaseBy(value) {
|
|
17
|
+
var amount = value != null ? value : 1;
|
|
18
|
+
var newValue = Math.max(counter + amount, 0);
|
|
19
|
+
if (initialValues != null && initialValues.maxCount) {
|
|
20
|
+
newValue = Math.min(newValue, initialValues.maxCount);
|
|
21
|
+
}
|
|
22
|
+
setCounter(newValue);
|
|
23
|
+
onChange && onChange({
|
|
24
|
+
count: newValue,
|
|
25
|
+
product: product
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
var reset = function reset() {
|
|
29
|
+
var newValue = (initialValues == null ? void 0 : initialValues.count) || value;
|
|
30
|
+
setCounter(newValue);
|
|
31
|
+
onChange && onChange({
|
|
32
|
+
count: newValue,
|
|
33
|
+
product: product
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
// El use ref se puede usar como un elemento que no tiene dependencias de renderizado
|
|
37
|
+
useEffect(function () {
|
|
38
|
+
if (!isMounted.current) return;
|
|
39
|
+
setCounter(value);
|
|
40
|
+
}, [value]);
|
|
41
|
+
useEffect(function () {
|
|
42
|
+
isMounted.current = true;
|
|
43
|
+
}, []);
|
|
44
|
+
return {
|
|
45
|
+
//Props
|
|
46
|
+
counter: counter,
|
|
47
|
+
maxCount: initialValues == null ? void 0 : initialValues.maxCount,
|
|
48
|
+
//Methods
|
|
49
|
+
increaseBy: increaseBy,
|
|
50
|
+
isMaxCountReached: !!(initialValues != null && initialValues.maxCount) && counter === initialValues.maxCount,
|
|
51
|
+
reset: reset
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function styleInject(css, ref) {
|
|
56
|
+
if ( ref === void 0 ) ref = {};
|
|
57
|
+
var insertAt = ref.insertAt;
|
|
58
|
+
|
|
59
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
60
|
+
|
|
61
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
62
|
+
var style = document.createElement('style');
|
|
63
|
+
style.type = 'text/css';
|
|
64
|
+
|
|
65
|
+
if (insertAt === 'top') {
|
|
66
|
+
if (head.firstChild) {
|
|
67
|
+
head.insertBefore(style, head.firstChild);
|
|
68
|
+
} else {
|
|
69
|
+
head.appendChild(style);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
head.appendChild(style);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (style.styleSheet) {
|
|
76
|
+
style.styleSheet.cssText = css;
|
|
77
|
+
} else {
|
|
78
|
+
style.appendChild(document.createTextNode(css));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var css_248z = ".styles-module_productCard__oaIVo {\n background-color: #1e2025;\n border-radius: 15px;\n box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.15);\n color: white;\n padding-bottom: 5px;\n font-family: Arial, Helvetica, sans-serif;\n width: 250px;\n margin-right: 5px;\n margin-top: 5px;\n}\n\n.styles-module_productImg__vPsTp {\n border-radius: 15px 15px 0px 0px;\n width: 100%;\n}\n\n.styles-module_productDescription__Ariub {\n margin: 10px;\n}\n\n.styles-module_buttonsContainer__ghCDF {\n margin: 10px;\n display: flex;\n flex-direction: row;\n}\n\n.styles-module_buttonMinus__BTgTf {\n cursor: pointer;\n background-color: transparent;\n border: 1px solid white;\n border-radius: 5px 0px 0px 5px;\n color: white;\n font-size: 20px;\n width: 30px;\n}\n\n.styles-module_buttonMinus__BTgTf:hover {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.styles-module_countLabel__S6HZ- {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n color: white;\n font-size: 16px;\n height: 25px;\n padding-top: 5px;\n text-align: center;\n width: 30px;\n}\n\n.styles-module_buttonAdd__s8wd6 {\n cursor: pointer;\n background-color: transparent;\n border: 1px solid white;\n border-radius: 0px 5px 5px 0px;\n color: white;\n font-size: 20px;\n width: 30px;\n}\n\n.styles-module_buttonAdd__s8wd6:hover {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.styles-module_disabled__k5aZm {\n border-color: grey !important;\n border-left: 1px solid white !important;\n color: grey !important;\n}\n";
|
|
83
|
+
var styles = {"productCard":"styles-module_productCard__oaIVo","productImg":"styles-module_productImg__vPsTp","productDescription":"styles-module_productDescription__Ariub","buttonsContainer":"styles-module_buttonsContainer__ghCDF","buttonMinus":"styles-module_buttonMinus__BTgTf","countLabel":"styles-module_countLabel__S6HZ-","buttonAdd":"styles-module_buttonAdd__s8wd6","disabled":"styles-module_disabled__k5aZm"};
|
|
84
|
+
styleInject(css_248z);
|
|
85
|
+
|
|
86
|
+
// ProductContext.tsx
|
|
87
|
+
var ProductContext = /*#__PURE__*/createContext({});
|
|
88
|
+
|
|
89
|
+
var DEFAULT_IMAGE = "https://via.placeholder.com/300x200?text=No+Image";
|
|
90
|
+
var ProductImage = function ProductImage(_ref) {
|
|
91
|
+
var img = _ref.img,
|
|
92
|
+
className = _ref.className,
|
|
93
|
+
style = _ref.style;
|
|
94
|
+
var _useContext = useContext(ProductContext),
|
|
95
|
+
product = _useContext.product;
|
|
96
|
+
var imgToShow = "";
|
|
97
|
+
if (img) {
|
|
98
|
+
imgToShow = img;
|
|
99
|
+
} else if (product.img) {
|
|
100
|
+
imgToShow = product.img;
|
|
101
|
+
} else {
|
|
102
|
+
imgToShow = DEFAULT_IMAGE;
|
|
103
|
+
}
|
|
104
|
+
return React.createElement("img", {
|
|
105
|
+
className: "\t" + styles.productImg + " " + className,
|
|
106
|
+
src: imgToShow,
|
|
107
|
+
alt: "Product",
|
|
108
|
+
style: style
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// export const ProductTitle = ({ title, className }: { title?: string, className?: string }): ReactElement => {
|
|
113
|
+
var ProductTitle = function ProductTitle(_ref) {
|
|
114
|
+
var title = _ref.title,
|
|
115
|
+
className = _ref.className,
|
|
116
|
+
style = _ref.style;
|
|
117
|
+
var _useContext = useContext(ProductContext),
|
|
118
|
+
product = _useContext.product;
|
|
119
|
+
return React.createElement("span", {
|
|
120
|
+
className: styles.productTitle + " " + className,
|
|
121
|
+
style: style
|
|
122
|
+
}, title || product.title);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
var ProductButtons = function ProductButtons(_ref) {
|
|
126
|
+
var className = _ref.className,
|
|
127
|
+
style = _ref.style;
|
|
128
|
+
var _useContext = useContext(ProductContext),
|
|
129
|
+
increaseBy = _useContext.increaseBy,
|
|
130
|
+
counter = _useContext.counter,
|
|
131
|
+
maxCount = _useContext.maxCount;
|
|
132
|
+
//TODO: Una función isMaxReached = useCallback, dependencias [counter, maxCounter]
|
|
133
|
+
//? True si el count === maxCount, caso contrario False
|
|
134
|
+
var isMaxReached = useCallback(function () {
|
|
135
|
+
return !!maxCount && counter === maxCount;
|
|
136
|
+
},
|
|
137
|
+
// retorna true o false
|
|
138
|
+
[counter, maxCount]);
|
|
139
|
+
return React.createElement("div", {
|
|
140
|
+
className: "\t" + styles.buttonsContainer + " " + className,
|
|
141
|
+
style: style
|
|
142
|
+
}, React.createElement("button", {
|
|
143
|
+
className: styles.buttonMinus,
|
|
144
|
+
onClick: function onClick() {
|
|
145
|
+
return increaseBy(-1);
|
|
146
|
+
}
|
|
147
|
+
}, "-"), React.createElement("div", {
|
|
148
|
+
className: styles.countLabel
|
|
149
|
+
}, counter), React.createElement("button", {
|
|
150
|
+
className: styles.buttonAdd + " " + (isMaxReached() && styles.disabled),
|
|
151
|
+
onClick: function onClick() {
|
|
152
|
+
return increaseBy(1);
|
|
153
|
+
}
|
|
154
|
+
}, "+"));
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
var Provider = ProductContext.Provider;
|
|
158
|
+
var ProductCard = function ProductCard(_ref) {
|
|
159
|
+
var children = _ref.children,
|
|
160
|
+
product = _ref.product,
|
|
161
|
+
className = _ref.className,
|
|
162
|
+
style = _ref.style,
|
|
163
|
+
onChange = _ref.onChange,
|
|
164
|
+
value = _ref.value,
|
|
165
|
+
initialValues = _ref.initialValues;
|
|
166
|
+
var _useProduct = useProduct({
|
|
167
|
+
onChange: onChange,
|
|
168
|
+
product: product,
|
|
169
|
+
value: value,
|
|
170
|
+
initialValues: initialValues
|
|
171
|
+
}),
|
|
172
|
+
counter = _useProduct.counter,
|
|
173
|
+
increaseBy = _useProduct.increaseBy,
|
|
174
|
+
isMaxCountReached = _useProduct.isMaxCountReached,
|
|
175
|
+
maxCount = _useProduct.maxCount,
|
|
176
|
+
reset = _useProduct.reset;
|
|
177
|
+
return React.createElement(Provider, {
|
|
178
|
+
value: {
|
|
179
|
+
counter: counter,
|
|
180
|
+
increaseBy: increaseBy,
|
|
181
|
+
maxCount: maxCount,
|
|
182
|
+
product: product
|
|
183
|
+
}
|
|
184
|
+
}, React.createElement("div", {
|
|
185
|
+
className: styles.productCard + " " + className,
|
|
186
|
+
style: style
|
|
187
|
+
}, children({
|
|
188
|
+
count: counter,
|
|
189
|
+
isMaxCountReached: isMaxCountReached,
|
|
190
|
+
maxCount: initialValues == null ? void 0 : initialValues.maxCount,
|
|
191
|
+
product: product,
|
|
192
|
+
increaseBy: increaseBy,
|
|
193
|
+
reset: reset
|
|
194
|
+
})));
|
|
195
|
+
};
|
|
196
|
+
ProductCard.Image = ProductImage;
|
|
197
|
+
ProductCard.Title = ProductTitle;
|
|
198
|
+
ProductCard.Buttons = ProductButtons;
|
|
199
|
+
|
|
200
|
+
var ProductCard$1 = /*#__PURE__*/Object.assign(ProductCard, {
|
|
201
|
+
Button: ProductButtons,
|
|
202
|
+
Image: ProductImage,
|
|
203
|
+
Title: ProductTitle
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
export { ProductButtons, ProductCard$1 as ProductCard, ProductImage, ProductTitle };
|
|
207
|
+
//# sourceMappingURL=jcd-product-card.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jcd-product-card.esm.js","sources":["../src/hooks/useProduct.ts","../node_modules/style-inject/dist/style-inject.es.js","../src/components/ProductContext.tsx","../src/components/ProductImage.tsx","../src/components/ProductTitle.tsx","../src/components/ProductButtons.tsx","../src/components/ProductCard.tsx","../src/components/index.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\r\nimport { InitialValues, onChangeArgs, Product } from \"../interfaces/interfaces\";\r\n\r\ninterface useProductArgs {\r\n\tproduct: Product;\r\n\tonChange?: (args: onChangeArgs) => void;\r\n\tvalue?: number;\r\n\tinitialValues?: InitialValues;\r\n}\r\n\r\nexport const useProduct = ({\r\n\tonChange,\r\n\tproduct,\r\n\tvalue = 0,\r\n\tinitialValues,\r\n}: useProductArgs) => {\r\n\t// if (initialValues) {\r\n\t// \tvalue = initialValues.count || value;\r\n\t// }\r\n\r\n\tconst [counter, setCounter] = useState<number>(initialValues?.count || value);\r\n\r\n\tconst isMounted = useRef(false);\r\n\r\n\tconst increaseBy = (value?: number) => {\r\n\t\tconst amount = value ?? 1;\r\n\t\tlet newValue = Math.max(counter + amount, 0);\r\n\r\n\t\tif (initialValues?.maxCount) {\r\n\t\t\tnewValue = Math.min(newValue, initialValues.maxCount);\r\n\t\t}\r\n\r\n\t\tsetCounter(newValue);\r\n\r\n\t\tonChange && onChange({ count: newValue, product });\r\n\t};\r\n\r\n\tconst reset = () => {\r\n\t\tconst newValue = initialValues?.count || value;\r\n\t\tsetCounter(newValue);\r\n\t\tonChange && onChange({ count: newValue, product });\r\n\r\n\t}\r\n\r\n\t// El use ref se puede usar como un elemento que no tiene dependencias de renderizado\r\n\tuseEffect(() => {\r\n\t\tif (!isMounted.current) return;\r\n\t\tsetCounter(value);\r\n\t}, [value]);\r\n\r\n\tuseEffect(() => {\r\n\t\tisMounted.current = true;\r\n\t}, []);\r\n\r\n\treturn {\r\n\t\t//Props\r\n\t\tcounter,\r\n\t\tmaxCount: initialValues?.maxCount,\r\n\t\t//Methods\r\n\t\tincreaseBy,\r\n\t\tisMaxCountReached: !!initialValues?.maxCount && counter === initialValues.maxCount,\r\n\t\treset\r\n\t};\r\n};\r\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","// ProductContext.tsx\r\nimport { createContext } from \"react\";\r\nimport { ProductContextProps } from \"../interfaces/interfaces\";\r\n\r\nexport const ProductContext = createContext({} as ProductContextProps);","import React, { useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\n\r\n// import noImages from \"../assets/no-image.jpg\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\timg?: string;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\nconst DEFAULT_IMAGE =\r\n \"https://via.placeholder.com/300x200?text=No+Image\";\r\n\r\nexport const ProductImage = ({ img , className, style }: Props) => {\r\n\tconst { product } = useContext(ProductContext);\r\n\tlet imgToShow: string = \"\";\r\n\tif (img) {\r\n\t\timgToShow = img;\r\n\t} else if (product.img) {\r\n\t\timgToShow = product.img;\r\n\t} else {\r\n\t\timgToShow = DEFAULT_IMAGE;\r\n\t}\r\n\r\n\treturn <img className={`\t${styles.productImg} ${className}`} src={imgToShow} alt=\"Product\" style={style} />;\r\n};\r\n","import React, { ReactElement, useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\ttitle?: string;\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n}\r\n\r\n// export const ProductTitle = ({ title, className }: { title?: string, className?: string }): ReactElement => {\r\nexport const ProductTitle = ({ title, className, style }: Props): ReactElement => {\r\n\tconst { product } = useContext(ProductContext);\r\n\r\n\treturn (\r\n\t\t<span className={`${styles.productTitle} ${className}`} style={style}>\r\n\t\t\t{title || product.title}\r\n\t\t</span>\r\n\t);\r\n};\r\n\r\n\r\n","import React, { useCallback, useContext } from \"react\";\r\nimport styles from \"../styles/styles.module.css\";\r\nimport { ProductContext } from \"./ProductContext\";\r\n\r\nexport interface Props {\r\n\t// className para poder recibir estilos personalizados\r\n\tclassName?: string;\r\n\tstyle?: React.CSSProperties;\r\n\tactiveBtnClass?: string;\r\n}\r\n\r\nexport const ProductButtons = ({ className, style }: Props) => {\r\n\r\n\tconst { increaseBy, counter, maxCount } = useContext(ProductContext);\r\n\r\n//TODO: Una función isMaxReached = useCallback, dependencias [counter, maxCounter]\r\n//? True si el count === maxCount, caso contrario False\r\n\r\nconst isMaxReached = useCallback(\r\n\t() => !!maxCount && counter === maxCount, // retorna true o false\r\n\t[counter, maxCount],\r\n)\r\n\r\n\treturn (\r\n\t\t<div className={`\t${styles.buttonsContainer} ${className}`} style={style}>\r\n\t\t\t<button className={styles.buttonMinus} onClick={() => increaseBy(-1)}>\r\n\t\t\t\t-\r\n\t\t\t</button>\r\n\t\t\t<div className={styles.countLabel}>{counter}</div>\r\n\r\n\t\t\t<button className={`${styles.buttonAdd} ${ isMaxReached() && styles.disabled}`} onClick={() => increaseBy(1)}>\r\n\t\t\t\t+\r\n\t\t\t</button>\r\n\t\t</div>\r\n\t);\r\n};\r\n","import React, { JSX } from 'react';\r\nimport { useProduct } from '../hooks/useProduct';\r\nimport {\r\n InitialValues,\r\n onChangeArgs,\r\n Product,\r\n ProductCardHandlers,\r\n} from '../interfaces/interfaces';\r\nimport styles from '../styles/styles.module.css';\r\n\r\nimport { ProductImage } from './ProductImage';\r\nimport { ProductTitle } from './ProductTitle';\r\nimport { ProductButtons } from './ProductButtons';\r\nimport { ProductContext } from './ProductContext';\r\n\r\nconst { Provider } = ProductContext;\r\n\r\nexport interface Props {\r\n product: Product;\r\n // children?: ReactElement | ReactElement[];\r\n children: (args: ProductCardHandlers) => JSX.Element;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n onChange?: (args: onChangeArgs) => void;\r\n value?: number;\r\n initialValues?: InitialValues;\r\n}\r\n\r\nexport const ProductCard = ({\r\n children,\r\n product,\r\n className,\r\n style,\r\n onChange,\r\n value,\r\n initialValues,\r\n}: Props) => {\r\n const {\r\n counter,\r\n increaseBy,\r\n isMaxCountReached,\r\n maxCount,\r\n reset,\r\n } = useProduct({\r\n onChange,\r\n product,\r\n value,\r\n initialValues,\r\n });\r\n\r\n return (\r\n <Provider value={{ counter, increaseBy, maxCount, product }}>\r\n <div className={`${styles.productCard} ${className}`} style={style}>\r\n {/* {children} */}\r\n {children({\r\n count: counter,\r\n isMaxCountReached,\r\n maxCount: initialValues?.maxCount,\r\n product,\r\n increaseBy,\r\n reset,\r\n })}\r\n </div>\r\n </Provider>\r\n );\r\n};\r\n\r\nProductCard.Image = ProductImage;\r\nProductCard.Title = ProductTitle;\r\nProductCard.Buttons = ProductButtons;\r\n","import { ProductCard as ProductCardHOC } from './ProductCard';\r\nimport { ProductCardHOCProps } from '../interfaces/interfaces';\r\nimport { ProductButtons } from './ProductButtons';\r\nimport { ProductImage } from './ProductImage';\r\nimport { ProductTitle } from './ProductTitle';\r\nexport { ProductButtons } from './ProductButtons';\r\nexport { ProductImage } from './ProductImage';\r\nexport { ProductTitle } from './ProductTitle';\r\n\r\nexport const ProductCard: ProductCardHOCProps = Object.assign(ProductCardHOC, {\r\n Button: ProductButtons,\r\n Image: ProductImage,\r\n Title: ProductTitle,\r\n});\r\n\r\nexport default ProductCard;"],"names":["useProduct","_ref","onChange","product","_ref$value","value","initialValues","_useState","useState","count","counter","setCounter","isMounted","useRef","increaseBy","amount","newValue","Math","max","maxCount","min","reset","useEffect","current","isMaxCountReached","ProductContext","createContext","DEFAULT_IMAGE","ProductImage","img","className","style","_useContext","useContext","imgToShow","React","styles","productImg","src","alt","ProductTitle","title","productTitle","ProductButtons","isMaxReached","useCallback","buttonsContainer","buttonMinus","onClick","countLabel","buttonAdd","disabled","Provider","ProductCard","children","_useProduct","productCard","Image","Title","Buttons","Object","assign","ProductCardHOC","Button"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.0.1",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"typings": "dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"url": "https://github.com/tatan22/jcd-product-card",
|
|
12
|
+
"type": "git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://www.youtube.com/@tatancarduar",
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=10"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"start": "tsdx watch",
|
|
20
|
+
"build": "tsdx build",
|
|
21
|
+
"test": "tsdx test --passWithNoTests",
|
|
22
|
+
"test:watch": "tsdx test --watch --no-cache",
|
|
23
|
+
"lint": "tsdx lint",
|
|
24
|
+
"prepare": "tsdx build",
|
|
25
|
+
"size": "size-limit",
|
|
26
|
+
"analyze": "size-limit --why"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": ">=16"
|
|
30
|
+
},
|
|
31
|
+
"husky": {
|
|
32
|
+
"hooks": {
|
|
33
|
+
"pre-commit": "tsdx lint"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"prettier": {
|
|
37
|
+
"printWidth": 80,
|
|
38
|
+
"semi": true,
|
|
39
|
+
"singleQuote": true,
|
|
40
|
+
"trailingComma": "es5"
|
|
41
|
+
},
|
|
42
|
+
"name": "@tatan22/jcd-product-card",
|
|
43
|
+
"author": "Jhonatan Cardona",
|
|
44
|
+
"module": "dist/do-product-card.esm.js",
|
|
45
|
+
"size-limit": [
|
|
46
|
+
{
|
|
47
|
+
"path": "dist/do-product-card.cjs.production.min.js",
|
|
48
|
+
"limit": "10 KB"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"path": "dist/do-product-card.esm.js",
|
|
52
|
+
"limit": "10 KB"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@babel/preset-env": "^7.28.6",
|
|
57
|
+
"@babel/preset-react": "^7.28.5",
|
|
58
|
+
"@rollup/plugin-image": "^2.1.1",
|
|
59
|
+
"@size-limit/preset-small-lib": "^5.0.5",
|
|
60
|
+
"@testing-library/dom": "^10.4.1",
|
|
61
|
+
"@testing-library/react": "^16.3.1",
|
|
62
|
+
"@types/jest": "^30.0.0",
|
|
63
|
+
"@types/react": "^19.2.8",
|
|
64
|
+
"@types/react-dom": "^19.2.3",
|
|
65
|
+
"@types/react-test-renderer": "^19.1.0",
|
|
66
|
+
"babel-jest": "^30.2.0",
|
|
67
|
+
"husky": "^7.0.2",
|
|
68
|
+
"identity-obj-proxy": "^3.0.0",
|
|
69
|
+
"jest": "^30.2.0",
|
|
70
|
+
"react": "^19.2.3",
|
|
71
|
+
"react-dom": "^19.2.3",
|
|
72
|
+
"react-test-renderer": "^19.2.3",
|
|
73
|
+
"rollup-plugin-images": "^1.0.0",
|
|
74
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
75
|
+
"size-limit": "^5.0.5",
|
|
76
|
+
"ts-jest": "^29.4.6",
|
|
77
|
+
"tsdx": "^0.14.1",
|
|
78
|
+
"tslib": "^2.3.1",
|
|
79
|
+
"typescript": "^4.4.3"
|
|
80
|
+
},
|
|
81
|
+
"keywords": [
|
|
82
|
+
"product",
|
|
83
|
+
"card",
|
|
84
|
+
"tatancarduar",
|
|
85
|
+
"Jhonatan",
|
|
86
|
+
"Cardona"
|
|
87
|
+
],
|
|
88
|
+
"dependencies": {},
|
|
89
|
+
"jest": {
|
|
90
|
+
"moduleNameMapper": {
|
|
91
|
+
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "identity-obj-proxy",
|
|
92
|
+
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { useCallback, useContext } from "react";
|
|
2
|
+
import styles from "../styles/styles.module.css";
|
|
3
|
+
import { ProductContext } from "./ProductContext";
|
|
4
|
+
|
|
5
|
+
export interface Props {
|
|
6
|
+
// className para poder recibir estilos personalizados
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
activeBtnClass?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ProductButtons = ({ className, style }: Props) => {
|
|
13
|
+
|
|
14
|
+
const { increaseBy, counter, maxCount } = useContext(ProductContext);
|
|
15
|
+
|
|
16
|
+
//TODO: Una función isMaxReached = useCallback, dependencias [counter, maxCounter]
|
|
17
|
+
//? True si el count === maxCount, caso contrario False
|
|
18
|
+
|
|
19
|
+
const isMaxReached = useCallback(
|
|
20
|
+
() => !!maxCount && counter === maxCount, // retorna true o false
|
|
21
|
+
[counter, maxCount],
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className={` ${styles.buttonsContainer} ${className}`} style={style}>
|
|
26
|
+
<button className={styles.buttonMinus} onClick={() => increaseBy(-1)}>
|
|
27
|
+
-
|
|
28
|
+
</button>
|
|
29
|
+
<div className={styles.countLabel}>{counter}</div>
|
|
30
|
+
|
|
31
|
+
<button className={`${styles.buttonAdd} ${ isMaxReached() && styles.disabled}`} onClick={() => increaseBy(1)}>
|
|
32
|
+
+
|
|
33
|
+
</button>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React, { JSX } from 'react';
|
|
2
|
+
import { useProduct } from '../hooks/useProduct';
|
|
3
|
+
import {
|
|
4
|
+
InitialValues,
|
|
5
|
+
onChangeArgs,
|
|
6
|
+
Product,
|
|
7
|
+
ProductCardHandlers,
|
|
8
|
+
} from '../interfaces/interfaces';
|
|
9
|
+
import styles from '../styles/styles.module.css';
|
|
10
|
+
|
|
11
|
+
import { ProductImage } from './ProductImage';
|
|
12
|
+
import { ProductTitle } from './ProductTitle';
|
|
13
|
+
import { ProductButtons } from './ProductButtons';
|
|
14
|
+
import { ProductContext } from './ProductContext';
|
|
15
|
+
|
|
16
|
+
const { Provider } = ProductContext;
|
|
17
|
+
|
|
18
|
+
export interface Props {
|
|
19
|
+
product: Product;
|
|
20
|
+
// children?: ReactElement | ReactElement[];
|
|
21
|
+
children: (args: ProductCardHandlers) => JSX.Element;
|
|
22
|
+
className?: string;
|
|
23
|
+
style?: React.CSSProperties;
|
|
24
|
+
onChange?: (args: onChangeArgs) => void;
|
|
25
|
+
value?: number;
|
|
26
|
+
initialValues?: InitialValues;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const ProductCard = ({
|
|
30
|
+
children,
|
|
31
|
+
product,
|
|
32
|
+
className,
|
|
33
|
+
style,
|
|
34
|
+
onChange,
|
|
35
|
+
value,
|
|
36
|
+
initialValues,
|
|
37
|
+
}: Props) => {
|
|
38
|
+
const {
|
|
39
|
+
counter,
|
|
40
|
+
increaseBy,
|
|
41
|
+
isMaxCountReached,
|
|
42
|
+
maxCount,
|
|
43
|
+
reset,
|
|
44
|
+
} = useProduct({
|
|
45
|
+
onChange,
|
|
46
|
+
product,
|
|
47
|
+
value,
|
|
48
|
+
initialValues,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Provider value={{ counter, increaseBy, maxCount, product }}>
|
|
53
|
+
<div className={`${styles.productCard} ${className}`} style={style}>
|
|
54
|
+
{/* {children} */}
|
|
55
|
+
{children({
|
|
56
|
+
count: counter,
|
|
57
|
+
isMaxCountReached,
|
|
58
|
+
maxCount: initialValues?.maxCount,
|
|
59
|
+
product,
|
|
60
|
+
increaseBy,
|
|
61
|
+
reset,
|
|
62
|
+
})}
|
|
63
|
+
</div>
|
|
64
|
+
</Provider>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
ProductCard.Image = ProductImage;
|
|
69
|
+
ProductCard.Title = ProductTitle;
|
|
70
|
+
ProductCard.Buttons = ProductButtons;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import styles from "../styles/styles.module.css";
|
|
3
|
+
|
|
4
|
+
// import noImages from "../assets/no-image.jpg";
|
|
5
|
+
import { ProductContext } from "./ProductContext";
|
|
6
|
+
|
|
7
|
+
export interface Props {
|
|
8
|
+
img?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
style?: React.CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
const DEFAULT_IMAGE =
|
|
13
|
+
"https://via.placeholder.com/300x200?text=No+Image";
|
|
14
|
+
|
|
15
|
+
export const ProductImage = ({ img , className, style }: Props) => {
|
|
16
|
+
const { product } = useContext(ProductContext);
|
|
17
|
+
let imgToShow: string = "";
|
|
18
|
+
if (img) {
|
|
19
|
+
imgToShow = img;
|
|
20
|
+
} else if (product.img) {
|
|
21
|
+
imgToShow = product.img;
|
|
22
|
+
} else {
|
|
23
|
+
imgToShow = DEFAULT_IMAGE;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return <img className={` ${styles.productImg} ${className}`} src={imgToShow} alt="Product" style={style} />;
|
|
27
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { ReactElement, useContext } from "react";
|
|
2
|
+
import styles from "../styles/styles.module.css";
|
|
3
|
+
import { ProductContext } from "./ProductContext";
|
|
4
|
+
|
|
5
|
+
export interface Props {
|
|
6
|
+
title?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// export const ProductTitle = ({ title, className }: { title?: string, className?: string }): ReactElement => {
|
|
12
|
+
export const ProductTitle = ({ title, className, style }: Props): ReactElement => {
|
|
13
|
+
const { product } = useContext(ProductContext);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<span className={`${styles.productTitle} ${className}`} style={style}>
|
|
17
|
+
{title || product.title}
|
|
18
|
+
</span>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ProductCard as ProductCardHOC } from './ProductCard';
|
|
2
|
+
import { ProductCardHOCProps } from '../interfaces/interfaces';
|
|
3
|
+
import { ProductButtons } from './ProductButtons';
|
|
4
|
+
import { ProductImage } from './ProductImage';
|
|
5
|
+
import { ProductTitle } from './ProductTitle';
|
|
6
|
+
export { ProductButtons } from './ProductButtons';
|
|
7
|
+
export { ProductImage } from './ProductImage';
|
|
8
|
+
export { ProductTitle } from './ProductTitle';
|
|
9
|
+
|
|
10
|
+
export const ProductCard: ProductCardHOCProps = Object.assign(ProductCardHOC, {
|
|
11
|
+
Button: ProductButtons,
|
|
12
|
+
Image: ProductImage,
|
|
13
|
+
Title: ProductTitle,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export default ProductCard;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { InitialValues, onChangeArgs, Product } from "../interfaces/interfaces";
|
|
3
|
+
|
|
4
|
+
interface useProductArgs {
|
|
5
|
+
product: Product;
|
|
6
|
+
onChange?: (args: onChangeArgs) => void;
|
|
7
|
+
value?: number;
|
|
8
|
+
initialValues?: InitialValues;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const useProduct = ({
|
|
12
|
+
onChange,
|
|
13
|
+
product,
|
|
14
|
+
value = 0,
|
|
15
|
+
initialValues,
|
|
16
|
+
}: useProductArgs) => {
|
|
17
|
+
// if (initialValues) {
|
|
18
|
+
// value = initialValues.count || value;
|
|
19
|
+
// }
|
|
20
|
+
|
|
21
|
+
const [counter, setCounter] = useState<number>(initialValues?.count || value);
|
|
22
|
+
|
|
23
|
+
const isMounted = useRef(false);
|
|
24
|
+
|
|
25
|
+
const increaseBy = (value?: number) => {
|
|
26
|
+
const amount = value ?? 1;
|
|
27
|
+
let newValue = Math.max(counter + amount, 0);
|
|
28
|
+
|
|
29
|
+
if (initialValues?.maxCount) {
|
|
30
|
+
newValue = Math.min(newValue, initialValues.maxCount);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setCounter(newValue);
|
|
34
|
+
|
|
35
|
+
onChange && onChange({ count: newValue, product });
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const reset = () => {
|
|
39
|
+
const newValue = initialValues?.count || value;
|
|
40
|
+
setCounter(newValue);
|
|
41
|
+
onChange && onChange({ count: newValue, product });
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// El use ref se puede usar como un elemento que no tiene dependencias de renderizado
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!isMounted.current) return;
|
|
48
|
+
setCounter(value);
|
|
49
|
+
}, [value]);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
isMounted.current = true;
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
//Props
|
|
57
|
+
counter,
|
|
58
|
+
maxCount: initialValues?.maxCount,
|
|
59
|
+
//Methods
|
|
60
|
+
increaseBy,
|
|
61
|
+
isMaxCountReached: !!initialValues?.maxCount && counter === initialValues.maxCount,
|
|
62
|
+
reset
|
|
63
|
+
};
|
|
64
|
+
};
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { JSX, JSXElementConstructor, ReactElement } from 'react';
|
|
2
|
+
import { Props as ProductCardProps } from '../components/ProductCard';
|
|
3
|
+
import { Props as ProductTitleProps } from '../components/ProductTitle';
|
|
4
|
+
import { Props as ProductImageProps } from '../components/ProductImage';
|
|
5
|
+
import { Props as ProductButtonsProps } from '../components/ProductButtons';
|
|
6
|
+
|
|
7
|
+
export interface Product {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
img?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ProductContextProps {
|
|
14
|
+
counter: number;
|
|
15
|
+
maxCount?: number;
|
|
16
|
+
product: Product;
|
|
17
|
+
increaseBy: (value?: number) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ProductCardHOCProps {
|
|
21
|
+
({ children, product }: ProductCardProps): JSX.Element;
|
|
22
|
+
Image: (Props: ProductImageProps) => JSX.Element;
|
|
23
|
+
Button: (Props: ProductButtonsProps) => JSX.Element;
|
|
24
|
+
Title: (
|
|
25
|
+
Props: ProductTitleProps
|
|
26
|
+
) => ReactElement<unknown, string | JSXElementConstructor<any>>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface onChangeArgs {
|
|
30
|
+
product: Product;
|
|
31
|
+
count: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ProductsInCart extends Product {
|
|
35
|
+
count: number;
|
|
36
|
+
}
|
|
37
|
+
export interface InitialValues {
|
|
38
|
+
count?: number;
|
|
39
|
+
maxCount?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ProductCardHandlers {
|
|
43
|
+
count: number;
|
|
44
|
+
isMaxCountReached: boolean;
|
|
45
|
+
maxCount?: number;
|
|
46
|
+
product: Product;
|
|
47
|
+
increaseBy: (value: number) => void;
|
|
48
|
+
reset: () => void;
|
|
49
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
.productCard {
|
|
2
|
+
background-color: #1e2025;
|
|
3
|
+
border-radius: 15px;
|
|
4
|
+
box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.15);
|
|
5
|
+
color: white;
|
|
6
|
+
padding-bottom: 5px;
|
|
7
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
8
|
+
width: 250px;
|
|
9
|
+
margin-right: 5px;
|
|
10
|
+
margin-top: 5px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.productImg {
|
|
14
|
+
border-radius: 15px 15px 0px 0px;
|
|
15
|
+
width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.productDescription {
|
|
19
|
+
margin: 10px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.buttonsContainer {
|
|
23
|
+
margin: 10px;
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: row;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.buttonMinus {
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
background-color: transparent;
|
|
31
|
+
border: 1px solid white;
|
|
32
|
+
border-radius: 5px 0px 0px 5px;
|
|
33
|
+
color: white;
|
|
34
|
+
font-size: 20px;
|
|
35
|
+
width: 30px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.buttonMinus:hover {
|
|
39
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.countLabel {
|
|
43
|
+
border-bottom: 1px solid white;
|
|
44
|
+
border-top: 1px solid white;
|
|
45
|
+
color: white;
|
|
46
|
+
font-size: 16px;
|
|
47
|
+
height: 25px;
|
|
48
|
+
padding-top: 5px;
|
|
49
|
+
text-align: center;
|
|
50
|
+
width: 30px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.buttonAdd {
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
background-color: transparent;
|
|
56
|
+
border: 1px solid white;
|
|
57
|
+
border-radius: 0px 5px 5px 0px;
|
|
58
|
+
color: white;
|
|
59
|
+
font-size: 20px;
|
|
60
|
+
width: 30px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.buttonAdd:hover {
|
|
64
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.disabled {
|
|
68
|
+
border-color: grey !important;
|
|
69
|
+
border-left: 1px solid white !important;
|
|
70
|
+
color: grey !important;
|
|
71
|
+
}
|