@faststore/components 3.0.75 → 3.0.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/molecules/QuantitySelector/QuantitySelector.d.ts +8 -4
- package/dist/cjs/molecules/QuantitySelector/QuantitySelector.js +15 -15
- package/dist/cjs/molecules/QuantitySelector/QuantitySelector.js.map +1 -1
- package/dist/cjs/molecules/SkuSelector/useSkuSlug.js +44 -1
- package/dist/cjs/molecules/SkuSelector/useSkuSlug.js.map +1 -1
- package/dist/esm/molecules/QuantitySelector/QuantitySelector.d.ts +8 -4
- package/dist/esm/molecules/QuantitySelector/QuantitySelector.js +15 -15
- package/dist/esm/molecules/QuantitySelector/QuantitySelector.js.map +1 -1
- package/dist/esm/molecules/SkuSelector/useSkuSlug.js +44 -1
- package/dist/esm/molecules/SkuSelector/useSkuSlug.js.map +1 -1
- package/package.json +2 -2
- package/src/molecules/QuantitySelector/QuantitySelector.tsx +39 -34
- package/src/molecules/SkuSelector/useSkuSlug.ts +60 -5
|
@@ -20,11 +20,11 @@ export interface QuantitySelectorProps {
|
|
|
20
20
|
initial?: number;
|
|
21
21
|
/**
|
|
22
22
|
* Controls by how many units the value advances
|
|
23
|
-
|
|
23
|
+
*/
|
|
24
24
|
unitMultiplier?: number;
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
* Controls wheter you use or not the unitMultiplier
|
|
27
|
+
*/
|
|
28
28
|
useUnitMultiplier?: boolean;
|
|
29
29
|
/**
|
|
30
30
|
* Specifies that the whole quantity selector component should be disabled.
|
|
@@ -34,6 +34,10 @@ export interface QuantitySelectorProps {
|
|
|
34
34
|
* Event emitted when value is changed
|
|
35
35
|
*/
|
|
36
36
|
onChange?: (value: number) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Event emitted when value is out of the min and max bounds
|
|
39
|
+
*/
|
|
40
|
+
onValidateBlur?: (min: number, maxValue: number, quantity: number) => void;
|
|
37
41
|
}
|
|
38
|
-
declare const QuantitySelector: ({ max, min, unitMultiplier, useUnitMultiplier, initial, disabled, onChange, testId, ...otherProps }: QuantitySelectorProps) => React.JSX.Element;
|
|
42
|
+
declare const QuantitySelector: ({ max, min, unitMultiplier, useUnitMultiplier, initial, disabled, onChange, onValidateBlur, testId, ...otherProps }: QuantitySelectorProps) => React.JSX.Element;
|
|
39
43
|
export default QuantitySelector;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
5
|
const __1 = require("../../");
|
|
6
|
-
const QuantitySelector = ({ max, min = 1, unitMultiplier = 1, useUnitMultiplier, initial, disabled = false, onChange, testId = 'fs-quantity-selector', ...otherProps }) => {
|
|
6
|
+
const QuantitySelector = ({ max, min = 1, unitMultiplier = 1, useUnitMultiplier, initial, disabled = false, onChange, onValidateBlur, testId = 'fs-quantity-selector', ...otherProps }) => {
|
|
7
7
|
const [quantity, setQuantity] = (0, react_1.useState)(initial ?? min);
|
|
8
8
|
const [multipliedUnit, setMultipliedUnit] = (0, react_1.useState)(quantity * unitMultiplier);
|
|
9
9
|
const roundUpQuantityIfNeeded = (quantity) => {
|
|
@@ -24,33 +24,33 @@ const QuantitySelector = ({ max, min = 1, unitMultiplier = 1, useUnitMultiplier,
|
|
|
24
24
|
const decrease = () => changeQuantity(-1);
|
|
25
25
|
function validateQuantityBounds(n) {
|
|
26
26
|
const maxValue = min ? Math.max(n, min) : n;
|
|
27
|
-
return max
|
|
27
|
+
return max
|
|
28
|
+
? Math.min(maxValue, useUnitMultiplier ? max * unitMultiplier : max)
|
|
29
|
+
: maxValue;
|
|
28
30
|
}
|
|
29
31
|
function validateBlur() {
|
|
30
|
-
const
|
|
32
|
+
const quantityValue = validateQuantityBounds(quantity);
|
|
33
|
+
const roundedQuantity = roundUpQuantityIfNeeded(quantityValue);
|
|
34
|
+
const maxValue = max ?? (min ? Math.max(quantity, min) : quantity);
|
|
35
|
+
const isOutOfBounds = quantity > maxValue || quantity < min;
|
|
36
|
+
if (isOutOfBounds) {
|
|
37
|
+
onValidateBlur?.(min, maxValue, roundedQuantity);
|
|
38
|
+
}
|
|
31
39
|
setQuantity(() => {
|
|
32
40
|
setMultipliedUnit(roundedQuantity);
|
|
33
41
|
onChange?.(roundedQuantity / unitMultiplier);
|
|
34
42
|
return roundedQuantity / unitMultiplier;
|
|
35
43
|
});
|
|
36
44
|
}
|
|
37
|
-
function validateInput(e) {
|
|
38
|
-
const val = e.currentTarget.value;
|
|
39
|
-
if (!Number.isNaN(Number(val))) {
|
|
40
|
-
setQuantity(() => {
|
|
41
|
-
const quantityValue = validateQuantityBounds(Number(val));
|
|
42
|
-
setMultipliedUnit(quantityValue);
|
|
43
|
-
onChange?.(quantityValue);
|
|
44
|
-
return quantityValue;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
45
|
(0, react_1.useEffect)(() => {
|
|
49
46
|
initial && setQuantity(initial);
|
|
50
47
|
}, [initial]);
|
|
48
|
+
const changeInputValue = (e) => {
|
|
49
|
+
setQuantity(Number(e.currentTarget.value));
|
|
50
|
+
};
|
|
51
51
|
return (react_1.default.createElement("div", { "data-fs-quantity-selector": disabled ? 'disabled' : 'true', "data-testid": testId, ...otherProps },
|
|
52
52
|
react_1.default.createElement(__1.IconButton, { "data-quantity-selector-button": "left", icon: react_1.default.createElement(__1.Icon, { name: "Minus", width: 16, height: 16, weight: "bold" }), "aria-label": "Decrement Quantity", "aria-controls": "quantity-selector-input", disabled: isLeftDisabled || disabled, onClick: decrease, testId: `${testId}-left-button`, size: "small" }),
|
|
53
|
-
react_1.default.createElement(__1.Input, { "data-quantity-selector-input": true, id: "quantity-selector-input", "aria-label": "Quantity", value: useUnitMultiplier ? multipliedUnit : quantity, onChange:
|
|
53
|
+
react_1.default.createElement(__1.Input, { "data-quantity-selector-input": true, id: "quantity-selector-input", "aria-label": "Quantity", value: useUnitMultiplier ? multipliedUnit : quantity, onChange: changeInputValue, onBlur: validateBlur, disabled: disabled }),
|
|
54
54
|
react_1.default.createElement(__1.IconButton, { "data-quantity-selector-button": "right", "aria-controls": "quantity-selector-input", "aria-label": "Increment Quantity", disabled: isRightDisabled || disabled, icon: react_1.default.createElement(__1.Icon, { name: "Plus", width: 16, height: 16, weight: "bold" }), onClick: increase, testId: `${testId}-right-button`, size: "small" })));
|
|
55
55
|
};
|
|
56
56
|
exports.default = QuantitySelector;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuantitySelector.js","sourceRoot":"","sources":["../../../../src/molecules/QuantitySelector/QuantitySelector.tsx"],"names":[],"mappings":";;;AAAA,uDAAkD;AAElD,8BAAgD;
|
|
1
|
+
{"version":3,"file":"QuantitySelector.js","sourceRoot":"","sources":["../../../../src/molecules/QuantitySelector/QuantitySelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -8,9 +8,52 @@ function getSkuSlug(slugsMap, selectedVariations, dominantVariation) {
|
|
|
8
8
|
return slugsMap[slugsMapKey];
|
|
9
9
|
}
|
|
10
10
|
const possibleVariants = Object.keys(slugsMap);
|
|
11
|
-
const
|
|
11
|
+
const dominantVariationKeyValue = `${dominantVariation}-${selectedVariations[dominantVariation]}`;
|
|
12
|
+
const slugVariationsForDominantValue = possibleVariants.filter((slug) => slug.includes(dominantVariationKeyValue));
|
|
13
|
+
const firstVariationForDominantValue = slugVariationsForDominantValue.length > 1
|
|
14
|
+
? getBestMatchVariation(slugVariationsForDominantValue, dominantVariationKeyValue)
|
|
15
|
+
: slugVariationsForDominantValue[0];
|
|
12
16
|
return slugsMap[firstVariationForDominantValue ?? possibleVariants[0]];
|
|
13
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* This function transforms a slug string into a record object.
|
|
20
|
+
* e.g. 'Color-Red-Size-40' => { Color: 'Red', Size: '40' }
|
|
21
|
+
* @param slug
|
|
22
|
+
* @returns the record object
|
|
23
|
+
*/
|
|
24
|
+
function transformSkuVariationsSlugToRecord(slug) {
|
|
25
|
+
const obj = {};
|
|
26
|
+
const parts = slug.split('-');
|
|
27
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
28
|
+
const key = parts[i].trim();
|
|
29
|
+
const value = parts[i + 1] ? parts[i + 1].trim() : '';
|
|
30
|
+
obj[key] = value;
|
|
31
|
+
}
|
|
32
|
+
return obj;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* This function receives a list of slug variations and a dominant variation key-value pair.
|
|
36
|
+
* It returns the exact match variation value for the dominant value.
|
|
37
|
+
* This happens when there are multiple variations filtered by the includes function (e.g. 7 is included in 7 and in 7.5).
|
|
38
|
+
*
|
|
39
|
+
*
|
|
40
|
+
* e.g. given the following params:
|
|
41
|
+
* slugVariationsForDominantValue = ['Color-Red-Size-7.5', 'Color-Blue-Size-7'],
|
|
42
|
+
* dominantVariationKeyValue = 'Size-7'.
|
|
43
|
+
*
|
|
44
|
+
* The function will return 'Color-Blue-Size-7'.
|
|
45
|
+
*
|
|
46
|
+
* @param slugVariationsForDominantValue
|
|
47
|
+
* @param dominantVariationKeyValue
|
|
48
|
+
* @returns the best match variation
|
|
49
|
+
*/
|
|
50
|
+
function getBestMatchVariation(slugVariationsForDominantValue, dominantVariationKeyValue) {
|
|
51
|
+
const [dominantKey, dominantValue] = dominantVariationKeyValue.split('-');
|
|
52
|
+
return slugVariationsForDominantValue.find((slug) => {
|
|
53
|
+
const slugRecord = transformSkuVariationsSlugToRecord(slug);
|
|
54
|
+
return slugRecord[dominantKey] === dominantValue;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
14
57
|
const useSkuSlug = (activeVariations, slugsMap, skuPropertyName, getItemHrefProp) => {
|
|
15
58
|
const getItemHref = (0, react_1.useCallback)((option) => {
|
|
16
59
|
if (getItemHrefProp)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSkuSlug.js","sourceRoot":"","sources":["../../../../src/molecules/SkuSelector/useSkuSlug.ts"],"names":[],"mappings":";;;AAAA,iCAAmC;AAGnC,SAAS,UAAU,CACjB,QAAgC,EAChC,kBAA0C,EAC1C,iBAAyB;IAEzB,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAEvE,IAAI,WAAW,IAAI,QAAQ,EAAE;QAC3B,OAAO,QAAQ,CAAC,WAAW,CAAC,CAAA;KAC7B;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE9C,MAAM,8BAA8B,GAAG,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"useSkuSlug.js","sourceRoot":"","sources":["../../../../src/molecules/SkuSelector/useSkuSlug.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,11 +20,11 @@ export interface QuantitySelectorProps {
|
|
|
20
20
|
initial?: number;
|
|
21
21
|
/**
|
|
22
22
|
* Controls by how many units the value advances
|
|
23
|
-
|
|
23
|
+
*/
|
|
24
24
|
unitMultiplier?: number;
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
* Controls wheter you use or not the unitMultiplier
|
|
27
|
+
*/
|
|
28
28
|
useUnitMultiplier?: boolean;
|
|
29
29
|
/**
|
|
30
30
|
* Specifies that the whole quantity selector component should be disabled.
|
|
@@ -34,6 +34,10 @@ export interface QuantitySelectorProps {
|
|
|
34
34
|
* Event emitted when value is changed
|
|
35
35
|
*/
|
|
36
36
|
onChange?: (value: number) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Event emitted when value is out of the min and max bounds
|
|
39
|
+
*/
|
|
40
|
+
onValidateBlur?: (min: number, maxValue: number, quantity: number) => void;
|
|
37
41
|
}
|
|
38
|
-
declare const QuantitySelector: ({ max, min, unitMultiplier, useUnitMultiplier, initial, disabled, onChange, testId, ...otherProps }: QuantitySelectorProps) => React.JSX.Element;
|
|
42
|
+
declare const QuantitySelector: ({ max, min, unitMultiplier, useUnitMultiplier, initial, disabled, onChange, onValidateBlur, testId, ...otherProps }: QuantitySelectorProps) => React.JSX.Element;
|
|
39
43
|
export default QuantitySelector;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import { Icon, IconButton, Input } from '../../';
|
|
3
|
-
const QuantitySelector = ({ max, min = 1, unitMultiplier = 1, useUnitMultiplier, initial, disabled = false, onChange, testId = 'fs-quantity-selector', ...otherProps }) => {
|
|
3
|
+
const QuantitySelector = ({ max, min = 1, unitMultiplier = 1, useUnitMultiplier, initial, disabled = false, onChange, onValidateBlur, testId = 'fs-quantity-selector', ...otherProps }) => {
|
|
4
4
|
const [quantity, setQuantity] = useState(initial ?? min);
|
|
5
5
|
const [multipliedUnit, setMultipliedUnit] = useState(quantity * unitMultiplier);
|
|
6
6
|
const roundUpQuantityIfNeeded = (quantity) => {
|
|
@@ -21,33 +21,33 @@ const QuantitySelector = ({ max, min = 1, unitMultiplier = 1, useUnitMultiplier,
|
|
|
21
21
|
const decrease = () => changeQuantity(-1);
|
|
22
22
|
function validateQuantityBounds(n) {
|
|
23
23
|
const maxValue = min ? Math.max(n, min) : n;
|
|
24
|
-
return max
|
|
24
|
+
return max
|
|
25
|
+
? Math.min(maxValue, useUnitMultiplier ? max * unitMultiplier : max)
|
|
26
|
+
: maxValue;
|
|
25
27
|
}
|
|
26
28
|
function validateBlur() {
|
|
27
|
-
const
|
|
29
|
+
const quantityValue = validateQuantityBounds(quantity);
|
|
30
|
+
const roundedQuantity = roundUpQuantityIfNeeded(quantityValue);
|
|
31
|
+
const maxValue = max ?? (min ? Math.max(quantity, min) : quantity);
|
|
32
|
+
const isOutOfBounds = quantity > maxValue || quantity < min;
|
|
33
|
+
if (isOutOfBounds) {
|
|
34
|
+
onValidateBlur?.(min, maxValue, roundedQuantity);
|
|
35
|
+
}
|
|
28
36
|
setQuantity(() => {
|
|
29
37
|
setMultipliedUnit(roundedQuantity);
|
|
30
38
|
onChange?.(roundedQuantity / unitMultiplier);
|
|
31
39
|
return roundedQuantity / unitMultiplier;
|
|
32
40
|
});
|
|
33
41
|
}
|
|
34
|
-
function validateInput(e) {
|
|
35
|
-
const val = e.currentTarget.value;
|
|
36
|
-
if (!Number.isNaN(Number(val))) {
|
|
37
|
-
setQuantity(() => {
|
|
38
|
-
const quantityValue = validateQuantityBounds(Number(val));
|
|
39
|
-
setMultipliedUnit(quantityValue);
|
|
40
|
-
onChange?.(quantityValue);
|
|
41
|
-
return quantityValue;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
42
|
useEffect(() => {
|
|
46
43
|
initial && setQuantity(initial);
|
|
47
44
|
}, [initial]);
|
|
45
|
+
const changeInputValue = (e) => {
|
|
46
|
+
setQuantity(Number(e.currentTarget.value));
|
|
47
|
+
};
|
|
48
48
|
return (React.createElement("div", { "data-fs-quantity-selector": disabled ? 'disabled' : 'true', "data-testid": testId, ...otherProps },
|
|
49
49
|
React.createElement(IconButton, { "data-quantity-selector-button": "left", icon: React.createElement(Icon, { name: "Minus", width: 16, height: 16, weight: "bold" }), "aria-label": "Decrement Quantity", "aria-controls": "quantity-selector-input", disabled: isLeftDisabled || disabled, onClick: decrease, testId: `${testId}-left-button`, size: "small" }),
|
|
50
|
-
React.createElement(Input, { "data-quantity-selector-input": true, id: "quantity-selector-input", "aria-label": "Quantity", value: useUnitMultiplier ? multipliedUnit : quantity, onChange:
|
|
50
|
+
React.createElement(Input, { "data-quantity-selector-input": true, id: "quantity-selector-input", "aria-label": "Quantity", value: useUnitMultiplier ? multipliedUnit : quantity, onChange: changeInputValue, onBlur: validateBlur, disabled: disabled }),
|
|
51
51
|
React.createElement(IconButton, { "data-quantity-selector-button": "right", "aria-controls": "quantity-selector-input", "aria-label": "Increment Quantity", disabled: isRightDisabled || disabled, icon: React.createElement(Icon, { name: "Plus", width: 16, height: 16, weight: "bold" }), onClick: increase, testId: `${testId}-right-button`, size: "small" })));
|
|
52
52
|
};
|
|
53
53
|
export default QuantitySelector;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuantitySelector.js","sourceRoot":"","sources":["../../../../src/molecules/QuantitySelector/QuantitySelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAElD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"QuantitySelector.js","sourceRoot":"","sources":["../../../../src/molecules/QuantitySelector/QuantitySelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -5,9 +5,52 @@ function getSkuSlug(slugsMap, selectedVariations, dominantVariation) {
|
|
|
5
5
|
return slugsMap[slugsMapKey];
|
|
6
6
|
}
|
|
7
7
|
const possibleVariants = Object.keys(slugsMap);
|
|
8
|
-
const
|
|
8
|
+
const dominantVariationKeyValue = `${dominantVariation}-${selectedVariations[dominantVariation]}`;
|
|
9
|
+
const slugVariationsForDominantValue = possibleVariants.filter((slug) => slug.includes(dominantVariationKeyValue));
|
|
10
|
+
const firstVariationForDominantValue = slugVariationsForDominantValue.length > 1
|
|
11
|
+
? getBestMatchVariation(slugVariationsForDominantValue, dominantVariationKeyValue)
|
|
12
|
+
: slugVariationsForDominantValue[0];
|
|
9
13
|
return slugsMap[firstVariationForDominantValue ?? possibleVariants[0]];
|
|
10
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* This function transforms a slug string into a record object.
|
|
17
|
+
* e.g. 'Color-Red-Size-40' => { Color: 'Red', Size: '40' }
|
|
18
|
+
* @param slug
|
|
19
|
+
* @returns the record object
|
|
20
|
+
*/
|
|
21
|
+
function transformSkuVariationsSlugToRecord(slug) {
|
|
22
|
+
const obj = {};
|
|
23
|
+
const parts = slug.split('-');
|
|
24
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
25
|
+
const key = parts[i].trim();
|
|
26
|
+
const value = parts[i + 1] ? parts[i + 1].trim() : '';
|
|
27
|
+
obj[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* This function receives a list of slug variations and a dominant variation key-value pair.
|
|
33
|
+
* It returns the exact match variation value for the dominant value.
|
|
34
|
+
* This happens when there are multiple variations filtered by the includes function (e.g. 7 is included in 7 and in 7.5).
|
|
35
|
+
*
|
|
36
|
+
*
|
|
37
|
+
* e.g. given the following params:
|
|
38
|
+
* slugVariationsForDominantValue = ['Color-Red-Size-7.5', 'Color-Blue-Size-7'],
|
|
39
|
+
* dominantVariationKeyValue = 'Size-7'.
|
|
40
|
+
*
|
|
41
|
+
* The function will return 'Color-Blue-Size-7'.
|
|
42
|
+
*
|
|
43
|
+
* @param slugVariationsForDominantValue
|
|
44
|
+
* @param dominantVariationKeyValue
|
|
45
|
+
* @returns the best match variation
|
|
46
|
+
*/
|
|
47
|
+
function getBestMatchVariation(slugVariationsForDominantValue, dominantVariationKeyValue) {
|
|
48
|
+
const [dominantKey, dominantValue] = dominantVariationKeyValue.split('-');
|
|
49
|
+
return slugVariationsForDominantValue.find((slug) => {
|
|
50
|
+
const slugRecord = transformSkuVariationsSlugToRecord(slug);
|
|
51
|
+
return slugRecord[dominantKey] === dominantValue;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
11
54
|
export const useSkuSlug = (activeVariations, slugsMap, skuPropertyName, getItemHrefProp) => {
|
|
12
55
|
const getItemHref = useCallback((option) => {
|
|
13
56
|
if (getItemHrefProp)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSkuSlug.js","sourceRoot":"","sources":["../../../../src/molecules/SkuSelector/useSkuSlug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAGnC,SAAS,UAAU,CACjB,QAAgC,EAChC,kBAA0C,EAC1C,iBAAyB;IAEzB,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAEvE,IAAI,WAAW,IAAI,QAAQ,EAAE;QAC3B,OAAO,QAAQ,CAAC,WAAW,CAAC,CAAA;KAC7B;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE9C,MAAM,8BAA8B,GAAG,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"useSkuSlug.js","sourceRoot":"","sources":["../../../../src/molecules/SkuSelector/useSkuSlug.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/components",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.81",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"module": "dist/esm/index.js",
|
|
6
6
|
"typings": "dist/esm/index.d.ts",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"volta": {
|
|
50
50
|
"extends": "../../package.json"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "2187237703ed2610a1d47a613d0a6ea62569b85f"
|
|
53
53
|
}
|
|
@@ -22,13 +22,13 @@ export interface QuantitySelectorProps {
|
|
|
22
22
|
*/
|
|
23
23
|
initial?: number
|
|
24
24
|
/**
|
|
25
|
-
* Controls by how many units the value advances
|
|
26
|
-
|
|
25
|
+
* Controls by how many units the value advances
|
|
26
|
+
*/
|
|
27
27
|
unitMultiplier?: number
|
|
28
|
-
|
|
29
|
-
* Controls wheter you use or not the unitMultiplier
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Controls wheter you use or not the unitMultiplier
|
|
30
|
+
*/
|
|
31
|
+
useUnitMultiplier?: boolean
|
|
32
32
|
/**
|
|
33
33
|
* Specifies that the whole quantity selector component should be disabled.
|
|
34
34
|
*/
|
|
@@ -37,6 +37,10 @@ export interface QuantitySelectorProps {
|
|
|
37
37
|
* Event emitted when value is changed
|
|
38
38
|
*/
|
|
39
39
|
onChange?: (value: number) => void
|
|
40
|
+
/**
|
|
41
|
+
* Event emitted when value is out of the min and max bounds
|
|
42
|
+
*/
|
|
43
|
+
onValidateBlur?: (min: number, maxValue: number, quantity: number) => void
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
const QuantitySelector = ({
|
|
@@ -47,21 +51,24 @@ const QuantitySelector = ({
|
|
|
47
51
|
initial,
|
|
48
52
|
disabled = false,
|
|
49
53
|
onChange,
|
|
54
|
+
onValidateBlur,
|
|
50
55
|
testId = 'fs-quantity-selector',
|
|
51
56
|
...otherProps
|
|
52
57
|
}: QuantitySelectorProps) => {
|
|
53
58
|
const [quantity, setQuantity] = useState<number>(initial ?? min)
|
|
54
|
-
const [multipliedUnit, setMultipliedUnit] = useState<number>(
|
|
59
|
+
const [multipliedUnit, setMultipliedUnit] = useState<number>(
|
|
60
|
+
quantity * unitMultiplier
|
|
61
|
+
)
|
|
55
62
|
|
|
56
63
|
const roundUpQuantityIfNeeded = (quantity: number) => {
|
|
57
|
-
if(!useUnitMultiplier){
|
|
64
|
+
if (!useUnitMultiplier) {
|
|
58
65
|
return quantity
|
|
59
66
|
}
|
|
60
|
-
return Math.ceil(quantity / unitMultiplier) * unitMultiplier
|
|
61
|
-
}
|
|
67
|
+
return Math.ceil(quantity / unitMultiplier) * unitMultiplier
|
|
68
|
+
}
|
|
62
69
|
|
|
63
70
|
const isLeftDisabled = quantity === min
|
|
64
|
-
const isRightDisabled = quantity === max
|
|
71
|
+
const isRightDisabled = quantity === max
|
|
65
72
|
|
|
66
73
|
const changeQuantity = (increaseValue: number) => {
|
|
67
74
|
const quantityValue = validateQuantityBounds(quantity + increaseValue)
|
|
@@ -70,7 +77,7 @@ const QuantitySelector = ({
|
|
|
70
77
|
setQuantity(quantityValue)
|
|
71
78
|
setMultipliedUnit(quantityValue * unitMultiplier)
|
|
72
79
|
}
|
|
73
|
-
|
|
80
|
+
|
|
74
81
|
const increase = () => changeQuantity(1)
|
|
75
82
|
|
|
76
83
|
const decrease = () => changeQuantity(-1)
|
|
@@ -78,39 +85,37 @@ const QuantitySelector = ({
|
|
|
78
85
|
function validateQuantityBounds(n: number): number {
|
|
79
86
|
const maxValue = min ? Math.max(n, min) : n
|
|
80
87
|
|
|
81
|
-
return max
|
|
88
|
+
return max
|
|
89
|
+
? Math.min(maxValue, useUnitMultiplier ? max * unitMultiplier : max)
|
|
90
|
+
: maxValue
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
function validateBlur() {
|
|
85
|
-
|
|
94
|
+
const quantityValue = validateQuantityBounds(quantity)
|
|
95
|
+
const roundedQuantity = roundUpQuantityIfNeeded(quantityValue)
|
|
86
96
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function validateInput(e: React.FormEvent<HTMLInputElement>) {
|
|
96
|
-
const val = e.currentTarget.value
|
|
97
|
+
const maxValue = max ?? (min ? Math.max(quantity, min) : quantity)
|
|
98
|
+
const isOutOfBounds = quantity > maxValue || quantity < min
|
|
99
|
+
if (isOutOfBounds) {
|
|
100
|
+
onValidateBlur?.(min, maxValue, roundedQuantity)
|
|
101
|
+
}
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
setMultipliedUnit(quantityValue)
|
|
102
|
-
onChange?.(quantityValue)
|
|
103
|
+
setQuantity(() => {
|
|
104
|
+
setMultipliedUnit(roundedQuantity)
|
|
105
|
+
onChange?.(roundedQuantity / unitMultiplier)
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
+
return roundedQuantity / unitMultiplier
|
|
108
|
+
})
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
|
|
110
111
|
useEffect(() => {
|
|
111
112
|
initial && setQuantity(initial)
|
|
112
113
|
}, [initial])
|
|
113
114
|
|
|
115
|
+
const changeInputValue = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
116
|
+
setQuantity(Number(e.currentTarget.value))
|
|
117
|
+
}
|
|
118
|
+
|
|
114
119
|
return (
|
|
115
120
|
<div
|
|
116
121
|
data-fs-quantity-selector={disabled ? 'disabled' : 'true'}
|
|
@@ -132,7 +137,7 @@ const QuantitySelector = ({
|
|
|
132
137
|
id="quantity-selector-input"
|
|
133
138
|
aria-label="Quantity"
|
|
134
139
|
value={useUnitMultiplier ? multipliedUnit : quantity}
|
|
135
|
-
onChange={
|
|
140
|
+
onChange={changeInputValue}
|
|
136
141
|
onBlur={validateBlur}
|
|
137
142
|
disabled={disabled}
|
|
138
143
|
/>
|
|
@@ -14,15 +14,70 @@ function getSkuSlug(
|
|
|
14
14
|
|
|
15
15
|
const possibleVariants = Object.keys(slugsMap)
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
17
|
+
const dominantVariationKeyValue = `${dominantVariation}-${selectedVariations[dominantVariation]}`
|
|
18
|
+
|
|
19
|
+
const slugVariationsForDominantValue = possibleVariants.filter((slug) =>
|
|
20
|
+
slug.includes(dominantVariationKeyValue)
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
const firstVariationForDominantValue =
|
|
24
|
+
slugVariationsForDominantValue.length > 1
|
|
25
|
+
? getBestMatchVariation(
|
|
26
|
+
slugVariationsForDominantValue,
|
|
27
|
+
dominantVariationKeyValue
|
|
28
|
+
)
|
|
29
|
+
: slugVariationsForDominantValue[0]
|
|
30
|
+
|
|
23
31
|
return slugsMap[firstVariationForDominantValue ?? possibleVariants[0]]
|
|
24
32
|
}
|
|
25
33
|
|
|
34
|
+
/**
|
|
35
|
+
* This function transforms a slug string into a record object.
|
|
36
|
+
* e.g. 'Color-Red-Size-40' => { Color: 'Red', Size: '40' }
|
|
37
|
+
* @param slug
|
|
38
|
+
* @returns the record object
|
|
39
|
+
*/
|
|
40
|
+
function transformSkuVariationsSlugToRecord(slug: string) {
|
|
41
|
+
const obj = {} as Record<string, string>
|
|
42
|
+
const parts = slug.split('-')
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
45
|
+
const key = parts[i].trim()
|
|
46
|
+
const value = parts[i + 1] ? parts[i + 1].trim() : ''
|
|
47
|
+
obj[key] = value
|
|
48
|
+
}
|
|
49
|
+
return obj
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* This function receives a list of slug variations and a dominant variation key-value pair.
|
|
54
|
+
* It returns the exact match variation value for the dominant value.
|
|
55
|
+
* This happens when there are multiple variations filtered by the includes function (e.g. 7 is included in 7 and in 7.5).
|
|
56
|
+
*
|
|
57
|
+
*
|
|
58
|
+
* e.g. given the following params:
|
|
59
|
+
* slugVariationsForDominantValue = ['Color-Red-Size-7.5', 'Color-Blue-Size-7'],
|
|
60
|
+
* dominantVariationKeyValue = 'Size-7'.
|
|
61
|
+
*
|
|
62
|
+
* The function will return 'Color-Blue-Size-7'.
|
|
63
|
+
*
|
|
64
|
+
* @param slugVariationsForDominantValue
|
|
65
|
+
* @param dominantVariationKeyValue
|
|
66
|
+
* @returns the best match variation
|
|
67
|
+
*/
|
|
68
|
+
function getBestMatchVariation(
|
|
69
|
+
slugVariationsForDominantValue: string[],
|
|
70
|
+
dominantVariationKeyValue: string
|
|
71
|
+
) {
|
|
72
|
+
const [dominantKey, dominantValue] = dominantVariationKeyValue.split('-')
|
|
73
|
+
|
|
74
|
+
return slugVariationsForDominantValue.find((slug) => {
|
|
75
|
+
const slugRecord = transformSkuVariationsSlugToRecord(slug)
|
|
76
|
+
|
|
77
|
+
return slugRecord[dominantKey] === dominantValue
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
26
81
|
export const useSkuSlug = (
|
|
27
82
|
activeVariations: Record<string, string>,
|
|
28
83
|
slugsMap: Record<string, string>,
|
|
@@ -31,7 +86,7 @@ export const useSkuSlug = (
|
|
|
31
86
|
) => {
|
|
32
87
|
const getItemHref = useCallback(
|
|
33
88
|
(option: SkuOption) => {
|
|
34
|
-
if(getItemHrefProp) return { getItemHrefProp }
|
|
89
|
+
if (getItemHrefProp) return { getItemHrefProp }
|
|
35
90
|
|
|
36
91
|
const currentItemHref = `/${getSkuSlug(
|
|
37
92
|
slugsMap,
|