@tapcart/mobile-components 0.8.49 → 0.8.50
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/components/ui/quantity-picker.d.ts +1 -3
- package/dist/components/ui/quantity-picker.d.ts.map +1 -1
- package/dist/components/ui/quantity-picker.js +12 -49
- package/dist/components/ui/quantity-pickerNEW.d.ts +25 -0
- package/dist/components/ui/quantity-pickerNEW.d.ts.map +1 -0
- package/dist/components/ui/quantity-pickerNEW.js +125 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lib/cart.util.d.ts +15 -8
- package/dist/lib/cart.util.d.ts.map +1 -1
- package/dist/lib/cart.util.js +12 -21
- package/dist/styles.css +10 -0
- package/package.json +1 -1
|
@@ -11,13 +11,11 @@ export interface QuantityPickerProps extends React.HTMLAttributes<HTMLDivElement
|
|
|
11
11
|
isIncreaseDisabled?: boolean;
|
|
12
12
|
loading?: boolean;
|
|
13
13
|
value: number;
|
|
14
|
-
|
|
15
|
-
onAdjustQuantity: (_: number) => void;
|
|
14
|
+
setValue: (_: number) => void;
|
|
16
15
|
className?: string;
|
|
17
16
|
inputStyle?: React.CSSProperties;
|
|
18
17
|
buttonStyle?: React.CSSProperties;
|
|
19
18
|
buttonCornerRadius?: number;
|
|
20
|
-
debounceTime?: number;
|
|
21
19
|
max?: number;
|
|
22
20
|
}
|
|
23
21
|
declare const QuantityPicker: React.ForwardRefExoticComponent<QuantityPickerProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quantity-picker.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"quantity-picker.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,MAAM,WAAW,mBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AA0ED,QAAA,MAAM,cAAc,4FA8HnB,CAAA;AAID,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -16,7 +16,6 @@ import { cn } from "../../lib/utils";
|
|
|
16
16
|
import { Icon } from "./icon";
|
|
17
17
|
import { useTap } from "./tap";
|
|
18
18
|
import { LoadingDots } from "./loading-dots";
|
|
19
|
-
import debounce from "lodash/debounce";
|
|
20
19
|
const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled }) => {
|
|
21
20
|
const { onTap, isPressed, ref: tapRef } = useTap();
|
|
22
21
|
const [isButtonPressed, setIsButtonPressed] = React.useState(false);
|
|
@@ -42,23 +41,14 @@ const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled })
|
|
|
42
41
|
}, disabled: disabled, "aria-label": "Quantity button" })] })));
|
|
43
42
|
};
|
|
44
43
|
const QuantityPicker = React.forwardRef((_a, ref) => {
|
|
45
|
-
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value,
|
|
44
|
+
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value, setValue, inputStyle, buttonStyle, buttonCornerRadius = 4, max = 99, loading = false } = _a, props = __rest(_a, ["className", "decreaseIconUrl", "increaseIconUrl", "deleteIconUrl", "isDeleteOnly", "iconColor", "onDecreaseClick", "onIncreaseClick", "isDecreaseDisabled", "isIncreaseDisabled", "value", "setValue", "inputStyle", "buttonStyle", "buttonCornerRadius", "max", "loading"]);
|
|
46
45
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
47
|
-
const
|
|
48
|
-
const [localInputValue, setLocalInputValue] = React.useState(value);
|
|
49
|
-
// Update local state when external value changes
|
|
46
|
+
const [localValue, setLocalValue] = React.useState(value.toString());
|
|
50
47
|
React.useEffect(() => {
|
|
51
|
-
if (
|
|
52
|
-
|
|
48
|
+
if (!isFocused) {
|
|
49
|
+
setLocalValue(value.toString());
|
|
53
50
|
}
|
|
54
|
-
}, [value]);
|
|
55
|
-
// Create debounced function for applying changes
|
|
56
|
-
const debouncedApplyChanges = React.useMemo(() => debounce(() => {
|
|
57
|
-
if (pendingQuantityAdjustment.current !== 0) {
|
|
58
|
-
onAdjustQuantity(pendingQuantityAdjustment.current);
|
|
59
|
-
pendingQuantityAdjustment.current = 0;
|
|
60
|
-
}
|
|
61
|
-
}, debounceTime), [debounceTime, onAdjustQuantity]);
|
|
51
|
+
}, [value, isFocused]);
|
|
62
52
|
const leftButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderTopLeftRadius: buttonCornerRadius
|
|
63
53
|
? `${buttonCornerRadius}px`
|
|
64
54
|
: undefined, borderBottomLeftRadius: buttonCornerRadius
|
|
@@ -70,56 +60,29 @@ const QuantityPicker = React.forwardRef((_a, ref) => {
|
|
|
70
60
|
? `${buttonCornerRadius}px`
|
|
71
61
|
: undefined });
|
|
72
62
|
const singleButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderRadius: buttonCornerRadius ? `${buttonCornerRadius}px` : undefined });
|
|
73
|
-
|
|
74
|
-
const newAmount = localInputValue + amount;
|
|
75
|
-
const clampedNewAmount = Math.min(Math.max(newAmount, 0), max);
|
|
76
|
-
// Update local value immediately
|
|
77
|
-
setLocalInputValue(clampedNewAmount);
|
|
78
|
-
// Track pending change for batched update
|
|
79
|
-
pendingQuantityAdjustment.current += amount;
|
|
80
|
-
// Trigger debounced API update
|
|
81
|
-
debouncedApplyChanges();
|
|
82
|
-
};
|
|
83
|
-
const handleDecreaseClick = (e) => {
|
|
84
|
-
e.preventDefault();
|
|
85
|
-
e.stopPropagation();
|
|
86
|
-
adjustQuantity(-1);
|
|
87
|
-
onDecreaseClick(e);
|
|
88
|
-
};
|
|
89
|
-
const handleIncreaseClick = (e) => {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
e.stopPropagation();
|
|
92
|
-
adjustQuantity(1);
|
|
93
|
-
onIncreaseClick(e);
|
|
94
|
-
};
|
|
95
|
-
return (_jsxs("div", Object.assign({ className: cn("flex relative", className), ref: ref }, props, { children: [isDeleteOnly ? (_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: deleteIconUrl, iconColor: iconColor, style: singleButtonStyle })) : (_jsxs(_Fragment, { children: [_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: localInputValue === 1 ? deleteIconUrl : decreaseIconUrl, iconColor: iconColor, style: leftButtonStyle, disabled: isDecreaseDisabled || loading }), _jsx("input", { type: "number", pattern: "[0-9]*", disabled: loading, max: max, value: localInputValue, onBlur: (e) => {
|
|
63
|
+
return (_jsxs("div", Object.assign({ className: cn("flex relative", className), ref: ref }, props, { children: [isDeleteOnly ? (_jsx(IconButton, { handler: onDecreaseClick, iconUrl: deleteIconUrl, iconColor: iconColor, style: singleButtonStyle })) : (_jsxs(_Fragment, { children: [_jsx(IconButton, { handler: onDecreaseClick, iconUrl: value === 1 ? deleteIconUrl : decreaseIconUrl, iconColor: iconColor, style: leftButtonStyle, disabled: isDecreaseDisabled || loading }), _jsx("input", { type: "number", pattern: "[0-9]*", disabled: loading, max: max, value: localValue, onBlur: (e) => {
|
|
96
64
|
setIsFocused(false);
|
|
97
65
|
const parsedValue = parseInt(e.target.value) || 0;
|
|
98
66
|
const clampedValue = Math.min(parsedValue, max);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Update and apply changes
|
|
102
|
-
const delta = clampedValue - value;
|
|
103
|
-
pendingQuantityAdjustment.current = delta;
|
|
104
|
-
setLocalInputValue(clampedValue);
|
|
105
|
-
onValueSet(clampedValue);
|
|
67
|
+
setValue(clampedValue);
|
|
68
|
+
setLocalValue(clampedValue.toString());
|
|
106
69
|
}, onFocus: () => {
|
|
107
70
|
setIsFocused(true);
|
|
108
71
|
}, onChange: (e) => {
|
|
109
72
|
const inputValue = e.target.value;
|
|
110
73
|
if (inputValue === "") {
|
|
111
|
-
|
|
74
|
+
setLocalValue("");
|
|
112
75
|
}
|
|
113
76
|
else {
|
|
114
77
|
const parsedValue = parseInt(inputValue);
|
|
115
78
|
if (!isNaN(parsedValue)) {
|
|
116
79
|
const clampedValue = Math.min(parsedValue, max);
|
|
117
|
-
|
|
80
|
+
setLocalValue(clampedValue.toString());
|
|
118
81
|
}
|
|
119
82
|
}
|
|
120
|
-
}, className: "w-8 h-7 focus-visible:outline-
|
|
83
|
+
}, className: "w-8 h-7 focus-visible:outline-none text-center bg-coreColors-inputBackground text-textColors-primaryColor border-t border-b border-coreColors-dividingLines", style: Object.assign(Object.assign({}, inputStyle), { borderRadius: (inputStyle === null || inputStyle === void 0 ? void 0 : inputStyle.borderRadius)
|
|
121
84
|
? `${inputStyle.borderRadius}px`
|
|
122
|
-
: 0 }), inputMode: "numeric" }), _jsx(IconButton, { handler:
|
|
85
|
+
: 0 }), inputMode: "numeric" }), _jsx(IconButton, { handler: onIncreaseClick, iconUrl: increaseIconUrl, iconColor: iconColor, style: rightButtonStyle, disabled: isIncreaseDisabled || loading })] })), _jsx(LoadingDots, { show: loading, size: 1, iconColor: iconColor })] })));
|
|
123
86
|
});
|
|
124
87
|
QuantityPicker.displayName = "QuantityPicker";
|
|
125
88
|
export { QuantityPicker };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface QuantityPickerNEWProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
decreaseIconUrl: string;
|
|
4
|
+
increaseIconUrl: string;
|
|
5
|
+
deleteIconUrl: string;
|
|
6
|
+
isDeleteOnly: boolean;
|
|
7
|
+
iconColor: string;
|
|
8
|
+
onDecreaseClick: React.ReactEventHandler;
|
|
9
|
+
onIncreaseClick: React.ReactEventHandler;
|
|
10
|
+
isDecreaseDisabled?: boolean;
|
|
11
|
+
isIncreaseDisabled?: boolean;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
value: number;
|
|
14
|
+
onValueSet: (_: number) => void;
|
|
15
|
+
onAdjustQuantity: (_: number) => void;
|
|
16
|
+
className?: string;
|
|
17
|
+
inputStyle?: React.CSSProperties;
|
|
18
|
+
buttonStyle?: React.CSSProperties;
|
|
19
|
+
buttonCornerRadius?: number;
|
|
20
|
+
debounceTime?: number;
|
|
21
|
+
max?: number;
|
|
22
|
+
}
|
|
23
|
+
declare const QuantityPickerNEW: React.ForwardRefExoticComponent<QuantityPickerNEWProps & React.RefAttributes<HTMLDivElement>>;
|
|
24
|
+
export { QuantityPickerNEW };
|
|
25
|
+
//# sourceMappingURL=quantity-pickerNEW.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quantity-pickerNEW.d.ts","sourceRoot":"","sources":["../../../components/ui/quantity-pickerNEW.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,WAAW,sBACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,eAAe,EAAE,KAAK,CAAC,iBAAiB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AA0ED,QAAA,MAAM,iBAAiB,+FAoLtB,CAAA;AAID,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
|
+
import * as React from "react";
|
|
15
|
+
import { cn } from "../../lib/utils";
|
|
16
|
+
import { Icon } from "./icon";
|
|
17
|
+
import { useTap } from "./tap";
|
|
18
|
+
import { LoadingDots } from "./loading-dots";
|
|
19
|
+
import debounce from "lodash/debounce";
|
|
20
|
+
const IconButton = ({ iconUrl, iconColor, handler, className, style, disabled }) => {
|
|
21
|
+
const { onTap, isPressed, ref: tapRef } = useTap();
|
|
22
|
+
const [isButtonPressed, setIsButtonPressed] = React.useState(false);
|
|
23
|
+
// Handle press state manually for the invisible button
|
|
24
|
+
const handleMouseDown = React.useCallback(() => {
|
|
25
|
+
if (!disabled)
|
|
26
|
+
setIsButtonPressed(true);
|
|
27
|
+
}, [disabled]);
|
|
28
|
+
const handleMouseUp = React.useCallback(() => {
|
|
29
|
+
setIsButtonPressed(false);
|
|
30
|
+
}, []);
|
|
31
|
+
// Calculate the visual styles for the button
|
|
32
|
+
const visualButtonStyle = Object.assign({}, style);
|
|
33
|
+
return (_jsxs("div", Object.assign({ className: "relative h-7 w-7", style: { touchAction: "manipulation" } }, { children: [_jsx("div", Object.assign({ className: cn("absolute inset-0 flex items-center justify-center bg-stateColors-skeleton border border-coreColors-dividingLines", className, disabled ? "opacity-50" : ""), style: visualButtonStyle, "aria-hidden": "true" }, { children: _jsx(Icon, { url: iconUrl, size: "sm", strokeColor: iconColor, strokeWidth: 4, style: {
|
|
34
|
+
opacity: isPressed || isButtonPressed ? 0.7 : 1,
|
|
35
|
+
} }) })), _jsx("button", { onClick: onTap(handler), onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onTouchStart: handleMouseDown, onTouchEnd: handleMouseUp, onTouchCancel: handleMouseUp, ref: tapRef, className: "absolute cursor-pointer", style: {
|
|
36
|
+
top: "-8px",
|
|
37
|
+
right: "-8px",
|
|
38
|
+
bottom: "-8px",
|
|
39
|
+
left: "-8px",
|
|
40
|
+
opacity: 0,
|
|
41
|
+
zIndex: 10,
|
|
42
|
+
}, disabled: disabled, "aria-label": "Quantity button" })] })));
|
|
43
|
+
};
|
|
44
|
+
const QuantityPickerNEW = React.forwardRef((_a, ref) => {
|
|
45
|
+
var { className, decreaseIconUrl, increaseIconUrl, deleteIconUrl, isDeleteOnly = false, iconColor, onDecreaseClick, onIncreaseClick, isDecreaseDisabled, isIncreaseDisabled, value, onValueSet, onAdjustQuantity, inputStyle, buttonStyle, buttonCornerRadius = 4, max = 99, loading = false, debounceTime = 300 } = _a, props = __rest(_a, ["className", "decreaseIconUrl", "increaseIconUrl", "deleteIconUrl", "isDeleteOnly", "iconColor", "onDecreaseClick", "onIncreaseClick", "isDecreaseDisabled", "isIncreaseDisabled", "value", "onValueSet", "onAdjustQuantity", "inputStyle", "buttonStyle", "buttonCornerRadius", "max", "loading", "debounceTime"]);
|
|
46
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
47
|
+
const pendingQuantityAdjustment = React.useRef(0);
|
|
48
|
+
const [localInputValue, setLocalInputValue] = React.useState(value);
|
|
49
|
+
// Update local state when external value changes
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
if (pendingQuantityAdjustment.current === 0) {
|
|
52
|
+
setLocalInputValue(value);
|
|
53
|
+
}
|
|
54
|
+
}, [value]);
|
|
55
|
+
// Create debounced function for applying changes
|
|
56
|
+
const debouncedApplyChanges = React.useMemo(() => debounce(() => {
|
|
57
|
+
if (pendingQuantityAdjustment.current !== 0) {
|
|
58
|
+
onAdjustQuantity(pendingQuantityAdjustment.current);
|
|
59
|
+
pendingQuantityAdjustment.current = 0;
|
|
60
|
+
}
|
|
61
|
+
}, debounceTime), [debounceTime, onAdjustQuantity]);
|
|
62
|
+
const leftButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderTopLeftRadius: buttonCornerRadius
|
|
63
|
+
? `${buttonCornerRadius}px`
|
|
64
|
+
: undefined, borderBottomLeftRadius: buttonCornerRadius
|
|
65
|
+
? `${buttonCornerRadius}px`
|
|
66
|
+
: undefined });
|
|
67
|
+
const rightButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderTopRightRadius: buttonCornerRadius
|
|
68
|
+
? `${buttonCornerRadius}px`
|
|
69
|
+
: undefined, borderBottomRightRadius: buttonCornerRadius
|
|
70
|
+
? `${buttonCornerRadius}px`
|
|
71
|
+
: undefined });
|
|
72
|
+
const singleButtonStyle = Object.assign(Object.assign({}, buttonStyle), { borderRadius: buttonCornerRadius ? `${buttonCornerRadius}px` : undefined });
|
|
73
|
+
const adjustQuantity = (amount) => {
|
|
74
|
+
const newAmount = localInputValue + amount;
|
|
75
|
+
const clampedNewAmount = Math.min(Math.max(newAmount, 0), max);
|
|
76
|
+
// Update local value immediately
|
|
77
|
+
setLocalInputValue(clampedNewAmount);
|
|
78
|
+
// Track pending change for batched update
|
|
79
|
+
pendingQuantityAdjustment.current += amount;
|
|
80
|
+
// Trigger debounced API update
|
|
81
|
+
debouncedApplyChanges();
|
|
82
|
+
};
|
|
83
|
+
const handleDecreaseClick = (e) => {
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
e.stopPropagation();
|
|
86
|
+
adjustQuantity(-1);
|
|
87
|
+
onDecreaseClick(e);
|
|
88
|
+
};
|
|
89
|
+
const handleIncreaseClick = (e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
e.stopPropagation();
|
|
92
|
+
adjustQuantity(1);
|
|
93
|
+
onIncreaseClick(e);
|
|
94
|
+
};
|
|
95
|
+
return (_jsxs("div", Object.assign({ className: cn("flex relative", className), ref: ref }, props, { children: [isDeleteOnly ? (_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: deleteIconUrl, iconColor: iconColor, style: singleButtonStyle })) : (_jsxs(_Fragment, { children: [_jsx(IconButton, { handler: handleDecreaseClick, iconUrl: localInputValue === 1 ? deleteIconUrl : decreaseIconUrl, iconColor: iconColor, style: leftButtonStyle, disabled: isDecreaseDisabled || loading }), _jsx("input", { type: "number", pattern: "[0-9]*", disabled: loading, max: max, value: localInputValue, onBlur: (e) => {
|
|
96
|
+
setIsFocused(false);
|
|
97
|
+
const parsedValue = parseInt(e.target.value) || 0;
|
|
98
|
+
const clampedValue = Math.min(parsedValue, max);
|
|
99
|
+
// Cancel any pending debounced operations
|
|
100
|
+
debouncedApplyChanges.cancel();
|
|
101
|
+
// Update and apply changes
|
|
102
|
+
const delta = clampedValue - value;
|
|
103
|
+
pendingQuantityAdjustment.current = delta;
|
|
104
|
+
setLocalInputValue(clampedValue);
|
|
105
|
+
onValueSet(clampedValue);
|
|
106
|
+
}, onFocus: () => {
|
|
107
|
+
setIsFocused(true);
|
|
108
|
+
}, onChange: (e) => {
|
|
109
|
+
const inputValue = e.target.value;
|
|
110
|
+
if (inputValue === "") {
|
|
111
|
+
setLocalInputValue(0);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const parsedValue = parseInt(inputValue);
|
|
115
|
+
if (!isNaN(parsedValue)) {
|
|
116
|
+
const clampedValue = Math.min(parsedValue, max);
|
|
117
|
+
setLocalInputValue(clampedValue);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}, className: "w-8 h-7 focus-visible:outline-no ne text-center bg-coreColors-inputBackground text-textColors-primaryColor border-t border-b border-coreColors-dividingLines", style: Object.assign(Object.assign({}, inputStyle), { borderRadius: (inputStyle === null || inputStyle === void 0 ? void 0 : inputStyle.borderRadius)
|
|
121
|
+
? `${inputStyle.borderRadius}px`
|
|
122
|
+
: 0 }), inputMode: "numeric" }), _jsx(IconButton, { handler: handleIncreaseClick, iconUrl: increaseIconUrl, iconColor: iconColor, style: rightButtonStyle, disabled: isIncreaseDisabled || loading || localInputValue >= max })] })), _jsx(LoadingDots, { show: loading, size: 1, iconColor: iconColor })] })));
|
|
123
|
+
});
|
|
124
|
+
QuantityPickerNEW.displayName = "QuantityPickerNEW";
|
|
125
|
+
export { QuantityPickerNEW };
|
package/dist/index.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export * from "./components/ui/portal";
|
|
|
46
46
|
export * from "./components/ui/price";
|
|
47
47
|
export * from "./components/ui/product-card";
|
|
48
48
|
export * from "./components/ui/quantity-picker";
|
|
49
|
+
export * from "./components/ui/quantity-pickerNEW";
|
|
49
50
|
export * from "./components/ui/progress-bar";
|
|
50
51
|
export * from "./components/ui/radio-group";
|
|
51
52
|
export * from "./components/ui/scroll-area";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,EAAE,EACF,GAAG,EACH,QAAQ,EACR,4BAA4B,EAC5B,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,yBAAyB,EACzB,4BAA4B,EAC5B,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,SAAS,EACT,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,2CAA2C,CAAA;AACzD,cAAc,mCAAmC,CAAA;AACjD,cAAc,wCAAwC,CAAA;AACtD,cAAc,0CAA0C,CAAA;AACxD,cAAc,wCAAwC,CAAA;AACtD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sCAAsC,CAAA;AACpD,cAAc,yCAAyC,CAAA;AACvD,cAAc,oCAAoC,CAAA;AAClD,cAAc,wCAAwC,CAAA;AACtD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sCAAsC,CAAA;AACpD,cAAc,oDAAoD,CAAA;AAClE,cAAc,kCAAkC,CAAA;AAChD,cAAc,2BAA2B,CAAA;AACzC,cAAc,mCAAmC,CAAA;AACjD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uCAAuC,CAAA;AACrD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uCAAuC,CAAA;AACrD,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,sCAAsC,CAAA;AACpD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,EAAE,EACF,GAAG,EACH,QAAQ,EACR,4BAA4B,EAC5B,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,yBAAyB,EACzB,4BAA4B,EAC5B,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAC5B,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,SAAS,EACT,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,2CAA2C,CAAA;AACzD,cAAc,mCAAmC,CAAA;AACjD,cAAc,wCAAwC,CAAA;AACtD,cAAc,0CAA0C,CAAA;AACxD,cAAc,wCAAwC,CAAA;AACtD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sCAAsC,CAAA;AACpD,cAAc,yCAAyC,CAAA;AACvD,cAAc,oCAAoC,CAAA;AAClD,cAAc,wCAAwC,CAAA;AACtD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sCAAsC,CAAA;AACpD,cAAc,oDAAoD,CAAA;AAClE,cAAc,kCAAkC,CAAA;AAChD,cAAc,2BAA2B,CAAA;AACzC,cAAc,mCAAmC,CAAA;AACjD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uCAAuC,CAAA;AACrD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uCAAuC,CAAA;AACrD,cAAc,sBAAsB,CAAA;AACpC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,sCAAsC,CAAA;AACpD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,iCAAiC,CAAA;AAE/C,cAAc,oCAAoC,CAAA;AAClD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sBAAsB,CAAA;AACpC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,kDAAkD,CAAA;AAChE,cAAc,gCAAgC,CAAA;AAC9C,cAAc,qCAAqC,CAAA;AACnD,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,aAAa,CAAA;AAC3B,cAAc,6CAA6C,CAAA;AAC3D,cAAc,kDAAkD,CAAA;AAChE,cAAc,qBAAqB,CAAA;AACnC,cAAc,mCAAmC,CAAA;AACjD,cAAc,qCAAqC,CAAA;AACnD,cAAc,wBAAwB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,8 @@ export * from "./components/ui/portal";
|
|
|
47
47
|
export * from "./components/ui/price";
|
|
48
48
|
export * from "./components/ui/product-card";
|
|
49
49
|
export * from "./components/ui/quantity-picker";
|
|
50
|
+
// TODO: make this the default quantity picker after new CartLineItem component is released
|
|
51
|
+
export * from "./components/ui/quantity-pickerNEW";
|
|
50
52
|
export * from "./components/ui/progress-bar";
|
|
51
53
|
export * from "./components/ui/radio-group";
|
|
52
54
|
export * from "./components/ui/scroll-area";
|
package/dist/lib/cart.util.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import { EnrichedCart, CartCalculatedDiscount, CartCalculatedAppliedGiftCard } from "app-studio-types";
|
|
2
|
-
export declare const getVariantPrice: ({
|
|
3
|
-
variantPrice: number;
|
|
4
|
-
variantCompareAtPrice: number;
|
|
1
|
+
import { EnrichedCart, CartCalculatedDiscount, CartCalculatedAppliedGiftCard, ProductVariant } from "app-studio-types";
|
|
2
|
+
export declare const getVariantPrice: ({ quantity, variant, sellingPlanAllocation, }: {
|
|
5
3
|
quantity: number;
|
|
6
|
-
|
|
4
|
+
variant: ProductVariant;
|
|
7
5
|
sellingPlanAllocation?: {
|
|
8
6
|
priceAdjustments: {
|
|
9
|
-
perDeliveryPrice?:
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
perDeliveryPrice?: {
|
|
8
|
+
amount: string;
|
|
9
|
+
currencyCode: string;
|
|
10
|
+
};
|
|
11
|
+
price: {
|
|
12
|
+
amount: string;
|
|
13
|
+
currencyCode: string;
|
|
14
|
+
};
|
|
15
|
+
compareAtPrice?: {
|
|
16
|
+
amount: string;
|
|
17
|
+
currencyCode: string;
|
|
18
|
+
};
|
|
12
19
|
}[];
|
|
13
20
|
} | undefined;
|
|
14
21
|
}) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart.util.d.ts","sourceRoot":"","sources":["../../lib/cart.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,6BAA6B,
|
|
1
|
+
{"version":3,"file":"cart.util.d.ts","sourceRoot":"","sources":["../../lib/cart.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,6BAA6B,EAE7B,cAAc,EACf,MAAM,kBAAkB,CAAA;AAGzB,eAAO,MAAM,eAAe;cAKhB,MAAM;aACP,cAAc;;0BAEH;YAChB,gBAAgB,CAAC,EAAE;gBACjB,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;YACD,KAAK,EAAE;gBACL,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;YACD,cAAc,CAAC,EAAE;gBACf,MAAM,EAAE,MAAM,CAAA;gBACd,YAAY,EAAE,MAAM,CAAA;aACrB,CAAA;SACF,EAAE;;;;;;;CAgCN,CAAA;AA2CD,eAAO,MAAM,oBAAoB,SAAU,MAAM,QAAQ,YAAY,YAMpE,CAAA;AAED,eAAO,MAAM,kBAAkB,SAAU,MAAM,QAAQ,YAAY,YAMlE,CAAA;AAoHD,MAAM,MAAM,cAAc,GAAG;IAC3B,yBAAyB,EAAE,sBAAsB,EAAE,CAAA;IACnD,gBAAgB,EAAE,6BAA6B,EAAE,CAAA;IACjD,cAAc,EAAE,OAAO,CAAA;IACvB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,eAAO,MAAM,uBAAuB,EAAE,cAUrC,CAAA;AAED,eAAO,MAAM,qBAAqB,SAAU,YAAY,KAAG,cA8B1D,CAAA;AAGD,eAAO,MAAM,mBAAmB;eACnB,MAAM;;;;;aAEG,MAAM;eAAS,MAAM;;;;oBAIN,MAAM;0BAAgB,MAAM;;;eAElD,MAAM;;;;;gBAML,MAAM;cACR,MAAM;;cAEN,MAAM;;;0BAIM;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE;oBAC9C,MAAM;;;;YAsCzB,CAAA"}
|
package/dist/lib/cart.util.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { getIdFromGid } from "./utils";
|
|
2
|
-
export const getVariantPrice = ({
|
|
3
|
-
var _a;
|
|
2
|
+
export const getVariantPrice = ({ quantity, variant, sellingPlanAllocation = { priceAdjustments: [] }, }) => {
|
|
3
|
+
var _a, _b, _c, _d;
|
|
4
4
|
const isSubscription = ((_a = sellingPlanAllocation === null || sellingPlanAllocation === void 0 ? void 0 : sellingPlanAllocation.priceAdjustments) === null || _a === void 0 ? void 0 : _a.length) > 0;
|
|
5
5
|
if (isSubscription) {
|
|
6
6
|
const { perDeliveryPrice, price, compareAtPrice } = sellingPlanAllocation.priceAdjustments[0];
|
|
7
7
|
const effectivePrice = perDeliveryPrice || price;
|
|
8
|
-
const subscriptionUnitPrice = perDeliveryPrice || 0;
|
|
9
|
-
const effectiveCompareAtPrice = compareAtPrice ||
|
|
8
|
+
const subscriptionUnitPrice = parseFloat((perDeliveryPrice === null || perDeliveryPrice === void 0 ? void 0 : perDeliveryPrice.amount) || "0") || 0;
|
|
9
|
+
const effectiveCompareAtPrice = parseFloat((compareAtPrice === null || compareAtPrice === void 0 ? void 0 : compareAtPrice.amount) || "0") ||
|
|
10
|
+
parseFloat((price === null || price === void 0 ? void 0 : price.amount) || "0") ||
|
|
11
|
+
0;
|
|
10
12
|
return {
|
|
11
13
|
price: subscriptionUnitPrice * quantity,
|
|
12
14
|
compareAtPrice: effectiveCompareAtPrice * quantity,
|
|
13
|
-
currency: currencyCode,
|
|
15
|
+
currency: effectivePrice === null || effectivePrice === void 0 ? void 0 : effectivePrice.currencyCode,
|
|
14
16
|
isSale: subscriptionUnitPrice < effectiveCompareAtPrice,
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
|
-
const variantUnitPrice =
|
|
18
|
-
const variantComparePrice =
|
|
19
|
+
const variantUnitPrice = parseFloat((_b = variant === null || variant === void 0 ? void 0 : variant.price) === null || _b === void 0 ? void 0 : _b.amount) || 0;
|
|
20
|
+
const variantComparePrice = parseFloat((_c = variant === null || variant === void 0 ? void 0 : variant.compareAtPrice) === null || _c === void 0 ? void 0 : _c.amount) || 0;
|
|
19
21
|
return {
|
|
20
22
|
price: variantUnitPrice * quantity,
|
|
21
23
|
compareAtPrice: variantComparePrice * quantity,
|
|
22
|
-
currency: currencyCode,
|
|
24
|
+
currency: (_d = variant === null || variant === void 0 ? void 0 : variant.price) === null || _d === void 0 ? void 0 : _d.currencyCode,
|
|
23
25
|
isSale: variantUnitPrice < variantComparePrice,
|
|
24
26
|
};
|
|
25
27
|
};
|
|
@@ -79,21 +81,10 @@ const getAppliedGiftCards = (cart) => {
|
|
|
79
81
|
const getSalesAmount = (cart) => {
|
|
80
82
|
var _a;
|
|
81
83
|
return (_a = cart.items) === null || _a === void 0 ? void 0 : _a.reduce((acc, item) => {
|
|
82
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
83
84
|
const { compareAtPrice, price } = getVariantPrice({
|
|
84
85
|
quantity: item.quantity || 1,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
currencyCode: ((_f = (_e = item.variantDetails) === null || _e === void 0 ? void 0 : _e.price) === null || _f === void 0 ? void 0 : _f.currencyCode) || "USD",
|
|
88
|
-
sellingPlanAllocation: {
|
|
89
|
-
priceAdjustments: [
|
|
90
|
-
{
|
|
91
|
-
price: parseFloat(((_h = (_g = item.variantDetails) === null || _g === void 0 ? void 0 : _g.price) === null || _h === void 0 ? void 0 : _h.amount) || "0"),
|
|
92
|
-
compareAtPrice: parseFloat(((_k = (_j = item.variantDetails) === null || _j === void 0 ? void 0 : _j.compareAtPrice) === null || _k === void 0 ? void 0 : _k.amount) || "0"),
|
|
93
|
-
perDeliveryPrice: parseFloat(((_m = (_l = item.variantDetails) === null || _l === void 0 ? void 0 : _l.price) === null || _m === void 0 ? void 0 : _m.amount) || "0"),
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
},
|
|
86
|
+
variant: item.variantDetails,
|
|
87
|
+
sellingPlanAllocation: item.sellingPlanAllocation,
|
|
97
88
|
});
|
|
98
89
|
if (compareAtPrice && compareAtPrice > price) {
|
|
99
90
|
return acc + (compareAtPrice - price);
|
package/dist/styles.css
CHANGED
|
@@ -1065,6 +1065,9 @@ video {
|
|
|
1065
1065
|
.h-full {
|
|
1066
1066
|
height: 100%;
|
|
1067
1067
|
}
|
|
1068
|
+
.h-screen {
|
|
1069
|
+
height: 100vh;
|
|
1070
|
+
}
|
|
1068
1071
|
.max-h-\[200px\] {
|
|
1069
1072
|
max-height: 200px;
|
|
1070
1073
|
}
|
|
@@ -1991,6 +1994,9 @@ video {
|
|
|
1991
1994
|
font-size: 0.75rem;
|
|
1992
1995
|
line-height: 1rem;
|
|
1993
1996
|
}
|
|
1997
|
+
.font-bold {
|
|
1998
|
+
font-weight: 700;
|
|
1999
|
+
}
|
|
1994
2000
|
.font-medium {
|
|
1995
2001
|
font-weight: 500;
|
|
1996
2002
|
}
|
|
@@ -2183,6 +2189,10 @@ video {
|
|
|
2183
2189
|
.text-textColors-strikethroughPriceText {
|
|
2184
2190
|
color: var(--textColors-strikethroughPriceText);
|
|
2185
2191
|
}
|
|
2192
|
+
.text-white {
|
|
2193
|
+
--tw-text-opacity: 1;
|
|
2194
|
+
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
|
2195
|
+
}
|
|
2186
2196
|
.underline {
|
|
2187
2197
|
text-decoration-line: underline;
|
|
2188
2198
|
}
|