@yahoo/uds-mobile 2.23.2 → 2.23.3
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/BottomSheet/BottomSheet.cjs +1 -1
- package/dist/components/BottomSheet/BottomSheet.js +1 -1
- package/dist/components/Button/buttonTheme.cjs +48 -21
- package/dist/components/Button/buttonTheme.d.cts +15 -10
- package/dist/components/Button/buttonTheme.d.cts.map +1 -1
- package/dist/components/Button/buttonTheme.d.ts +15 -10
- package/dist/components/Button/buttonTheme.d.ts.map +1 -1
- package/dist/components/Button/buttonTheme.js +47 -21
- package/dist/components/Button/buttonTheme.js.map +1 -1
- package/dist/components/Button.cjs +17 -9
- package/dist/components/Button.d.cts.map +1 -1
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +17 -9
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Icon.cjs +3 -2
- package/dist/components/Icon.d.cts.map +1 -1
- package/dist/components/Icon.d.ts.map +1 -1
- package/dist/components/Icon.js +3 -2
- package/dist/components/Icon.js.map +1 -1
- package/dist/components/IconButton.cjs +18 -8
- package/dist/components/IconButton.js +18 -8
- package/dist/components/IconButton.js.map +1 -1
- package/dist/components/internal/Overlay/index.cjs +1 -1
- package/dist/components/internal/Overlay/index.js +1 -1
- package/dist/mobile/generated/fontMetrics.cjs +1166 -0
- package/dist/mobile/generated/fontMetrics.js +1168 -0
- package/dist/mobile/generated/fontMetrics.js.map +1 -0
- package/generated/fontMetrics.ts +1173 -0
- package/package.json +1 -1
|
@@ -21,8 +21,8 @@ let generated_styles = require("../../../generated/styles");
|
|
|
21
21
|
let react_native_reanimated = require("react-native-reanimated");
|
|
22
22
|
react_native_reanimated = require_runtime.__toESM(react_native_reanimated);
|
|
23
23
|
let react_native_gesture_handler = require("react-native-gesture-handler");
|
|
24
|
-
let react_native_safe_area_context = require("react-native-safe-area-context");
|
|
25
24
|
let react_native_screens = require("react-native-screens");
|
|
25
|
+
let react_native_safe_area_context = require("react-native-safe-area-context");
|
|
26
26
|
//#region src/components/BottomSheet/BottomSheet.tsx
|
|
27
27
|
function useScreenCornerRadius() {
|
|
28
28
|
const [, forceUpdate] = (0, react.useState)(0);
|
|
@@ -18,8 +18,8 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
18
18
|
import { bottomSheetStyles } from "../../../generated/styles";
|
|
19
19
|
import Animated, { interpolate, useAnimatedStyle, useSharedValue } from "react-native-reanimated";
|
|
20
20
|
import { GestureDetector, GestureHandlerRootView } from "react-native-gesture-handler";
|
|
21
|
-
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
22
21
|
import { FullWindowOverlay } from "react-native-screens";
|
|
22
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
23
23
|
//#region src/components/BottomSheet/BottomSheet.tsx
|
|
24
24
|
function useScreenCornerRadius() {
|
|
25
25
|
const [, forceUpdate] = useState(0);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const require_fontMetrics = require("../../mobile/generated/fontMetrics.cjs");
|
|
3
4
|
//#region src/components/Button/buttonTheme.ts
|
|
4
5
|
const SHARED_BUTTON_ICONBUTTON_SIZES = new Set([
|
|
5
6
|
"xs",
|
|
@@ -7,6 +8,7 @@ const SHARED_BUTTON_ICONBUTTON_SIZES = new Set([
|
|
|
7
8
|
"md",
|
|
8
9
|
"lg"
|
|
9
10
|
]);
|
|
11
|
+
const UNKNOWN_FONT_LINE_HEIGHT_RATIO = 1.3;
|
|
10
12
|
function buttonSizePath(size, layer) {
|
|
11
13
|
return `button/size/${size}/${layer}/rest`;
|
|
12
14
|
}
|
|
@@ -23,47 +25,72 @@ function getIconSize(iconStyle) {
|
|
|
23
25
|
function getVerticalPadding(rootStyle) {
|
|
24
26
|
return (typeof rootStyle.paddingVertical === "number" ? rootStyle.paddingVertical : void 0) ?? (typeof rootStyle.padding === "number" ? rootStyle.padding : void 0) ?? 0;
|
|
25
27
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
function getMetricHeight(value, unitsPerEm, fontSize) {
|
|
29
|
+
return Math.ceil(Math.max(0, value) / unitsPerEm * fontSize);
|
|
30
|
+
}
|
|
31
|
+
function getSafeLabelLineHeight(textStyle, fallbackFontSize) {
|
|
32
|
+
const fontSize = typeof textStyle.fontSize === "number" ? textStyle.fontSize : fallbackFontSize;
|
|
33
|
+
const tokenLineHeight = typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : fontSize;
|
|
34
|
+
const metrics = typeof textStyle.fontFamily === "string" ? require_fontMetrics.fontMetrics[textStyle.fontFamily] : void 0;
|
|
35
|
+
if (!metrics || metrics.unitsPerEm <= 0) return Math.max(tokenLineHeight, Math.ceil(fontSize * UNKNOWN_FONT_LINE_HEIGHT_RATIO));
|
|
36
|
+
const metricsLineHeight = getMetricHeight(metrics.ascent, metrics.unitsPerEm, fontSize) + getMetricHeight(-metrics.descent, metrics.unitsPerEm, fontSize) + getMetricHeight(metrics.lineGap, metrics.unitsPerEm, fontSize);
|
|
37
|
+
return Math.max(tokenLineHeight, metricsLineHeight);
|
|
30
38
|
}
|
|
31
|
-
/**
|
|
39
|
+
/** Safe line box for the icon font's em square plus any bbox overflow. */
|
|
40
|
+
function getSafeIconCell(fontSize) {
|
|
41
|
+
const metrics = require_fontMetrics.fontMetrics["uds-icons"];
|
|
42
|
+
if (!metrics || metrics.unitsPerEm <= 0) return Math.ceil(fontSize * UNKNOWN_FONT_LINE_HEIGHT_RATIO);
|
|
43
|
+
const overflowAboveEm = Math.max(0, metrics.bbox.maxY - metrics.unitsPerEm);
|
|
44
|
+
const overflowBelowEm = Math.max(0, -metrics.bbox.minY);
|
|
45
|
+
return Math.ceil(fontSize) + getMetricHeight(overflowAboveEm, metrics.unitsPerEm, fontSize) + getMetricHeight(overflowBelowEm, metrics.unitsPerEm, fontSize);
|
|
46
|
+
}
|
|
47
|
+
/** Safe native content metrics while retaining the token-derived target control height. */
|
|
32
48
|
function getButtonControlMetrics(theme, size) {
|
|
33
49
|
const rootStyle = getLayerStyle(theme, buttonSizePath(size, "root"));
|
|
34
50
|
const iconStyle = getLayerStyle(theme, buttonSizePath(size, "icon"));
|
|
35
51
|
const textStyle = getLayerStyle(theme, buttonSizePath(size, "rootText"));
|
|
36
52
|
const paddingVertical = getVerticalPadding(rootStyle);
|
|
37
53
|
const iconSize = getIconSize(iconStyle);
|
|
38
|
-
const
|
|
54
|
+
const fontSize = typeof textStyle.fontSize === "number" ? textStyle.fontSize : iconSize;
|
|
55
|
+
const tokenLineHeight = typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : fontSize;
|
|
56
|
+
const targetContentHeight = Math.max(iconSize, tokenLineHeight);
|
|
57
|
+
const minHeight = Math.ceil(paddingVertical * 2 + targetContentHeight);
|
|
58
|
+
const labelLineHeight = getSafeLabelLineHeight(textStyle, iconSize);
|
|
59
|
+
const iconCellHeight = getSafeIconCell(iconSize);
|
|
39
60
|
return {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
61
|
+
minHeight,
|
|
62
|
+
labelLineHeight,
|
|
63
|
+
iconCellHeight,
|
|
64
|
+
paddingVertical: Math.max(0, (minHeight - Math.max(labelLineHeight, iconCellHeight)) / 2)
|
|
43
65
|
};
|
|
44
66
|
}
|
|
45
|
-
/**
|
|
67
|
+
/** Safe icon cell within the token-derived control size; explicit token height (match-button-height opt-in) wins as the target. */
|
|
46
68
|
function getIconButtonControlMetrics(theme, size) {
|
|
47
69
|
const rootStyle = getLayerStyle(theme, iconButtonSizePath(size, "root"));
|
|
48
|
-
const
|
|
70
|
+
const iconStyle = getLayerStyle(theme, iconButtonSizePath(size, "icon"));
|
|
71
|
+
const iconSize = getIconSize(iconStyle);
|
|
72
|
+
const tokenLineHeight = typeof iconStyle.lineHeight === "number" ? iconStyle.lineHeight : iconSize;
|
|
73
|
+
const paddingVertical = getVerticalPadding(rootStyle);
|
|
49
74
|
const explicitHeight = typeof rootStyle.height === "number" ? rootStyle.height : void 0;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
};
|
|
75
|
+
const hasExplicitHeight = SHARED_BUTTON_ICONBUTTON_SIZES.has(size) && explicitHeight !== void 0;
|
|
76
|
+
const minHeight = hasExplicitHeight ? explicitHeight : Math.ceil(paddingVertical * 2 + Math.max(iconSize, tokenLineHeight));
|
|
77
|
+
const iconCellHeight = getSafeIconCell(iconSize);
|
|
54
78
|
return {
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
minHeight,
|
|
80
|
+
iconCellHeight,
|
|
81
|
+
paddingVertical: Math.max(0, (minHeight - Math.max(iconSize, iconCellHeight)) / 2),
|
|
82
|
+
hasExplicitHeight
|
|
57
83
|
};
|
|
58
84
|
}
|
|
59
|
-
/**
|
|
60
|
-
function
|
|
85
|
+
/** Apply the metric-safe line height after the token typography styles. */
|
|
86
|
+
function getButtonTextStyle(textStyle, labelLineHeight) {
|
|
61
87
|
return {
|
|
62
88
|
...textStyle,
|
|
63
|
-
lineHeight:
|
|
89
|
+
lineHeight: labelLineHeight
|
|
64
90
|
};
|
|
65
91
|
}
|
|
66
92
|
//#endregion
|
|
67
93
|
exports.getButtonControlMetrics = getButtonControlMetrics;
|
|
68
|
-
exports.
|
|
94
|
+
exports.getButtonTextStyle = getButtonTextStyle;
|
|
69
95
|
exports.getIconButtonControlMetrics = getIconButtonControlMetrics;
|
|
96
|
+
exports.getSafeIconCell = getSafeIconCell;
|
|
@@ -6,19 +6,24 @@ import { TextStyle } from "react-native";
|
|
|
6
6
|
type ButtonTheme = {
|
|
7
7
|
components: Record<string, any>;
|
|
8
8
|
};
|
|
9
|
-
/**
|
|
9
|
+
/** Safe line box for the icon font's em square plus any bbox overflow. */
|
|
10
|
+
declare function getSafeIconCell(fontSize: number): number;
|
|
11
|
+
/** Safe native content metrics while retaining the token-derived target control height. */
|
|
10
12
|
declare function getButtonControlMetrics(theme: ButtonTheme, size: ButtonSize): {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
minHeight: number;
|
|
14
|
+
labelLineHeight: number;
|
|
15
|
+
iconCellHeight: number;
|
|
16
|
+
paddingVertical: number;
|
|
14
17
|
};
|
|
15
|
-
/**
|
|
18
|
+
/** Safe icon cell within the token-derived control size; explicit token height (match-button-height opt-in) wins as the target. */
|
|
16
19
|
declare function getIconButtonControlMetrics(theme: ButtonTheme, size: IconButtonSize): {
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
minHeight: number;
|
|
21
|
+
iconCellHeight: number;
|
|
22
|
+
paddingVertical: number;
|
|
23
|
+
hasExplicitHeight: boolean;
|
|
19
24
|
};
|
|
20
|
-
/**
|
|
21
|
-
declare function
|
|
25
|
+
/** Apply the metric-safe line height after the token typography styles. */
|
|
26
|
+
declare function getButtonTextStyle(textStyle: TextStyle, labelLineHeight: number): TextStyle;
|
|
22
27
|
//#endregion
|
|
23
|
-
export { getButtonControlMetrics,
|
|
28
|
+
export { getButtonControlMetrics, getButtonTextStyle, getIconButtonControlMetrics, getSafeIconCell };
|
|
24
29
|
//# sourceMappingURL=buttonTheme.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buttonTheme.d.cts","names":[],"sources":["../../../src/components/Button/buttonTheme.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"buttonTheme.d.cts","names":[],"sources":["../../../src/components/Button/buttonTheme.ts"],"mappings":";;;;;KAKK,WAAA;EAEH,UAAA,EAAY,MAAA;AAAA;;iBA4DE,eAAA,CAAgB,QAAA;;iBAiBhB,uBAAA,CACd,KAAA,EAAO,WAAA,EACP,IAAA,EAAM,UAAA;EAEN,SAAA;EACA,eAAA;EACA,cAAA;EACA,eAAA;AAAA;AAPF;AAAA,iBAgCgB,2BAAA,CACd,KAAA,EAAO,WAAA,EACP,IAAA,EAAM,cAAA;EAEN,SAAA;EACA,cAAA;EACA,eAAA;EACA,iBAAA;AAAA;;iBAyBc,kBAAA,CAAmB,SAAA,EAAW,SAAA,EAAW,eAAA,WAA0B,SAAA"}
|
|
@@ -6,19 +6,24 @@ import { TextStyle } from "react-native";
|
|
|
6
6
|
type ButtonTheme = {
|
|
7
7
|
components: Record<string, any>;
|
|
8
8
|
};
|
|
9
|
-
/**
|
|
9
|
+
/** Safe line box for the icon font's em square plus any bbox overflow. */
|
|
10
|
+
declare function getSafeIconCell(fontSize: number): number;
|
|
11
|
+
/** Safe native content metrics while retaining the token-derived target control height. */
|
|
10
12
|
declare function getButtonControlMetrics(theme: ButtonTheme, size: ButtonSize): {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
minHeight: number;
|
|
14
|
+
labelLineHeight: number;
|
|
15
|
+
iconCellHeight: number;
|
|
16
|
+
paddingVertical: number;
|
|
14
17
|
};
|
|
15
|
-
/**
|
|
18
|
+
/** Safe icon cell within the token-derived control size; explicit token height (match-button-height opt-in) wins as the target. */
|
|
16
19
|
declare function getIconButtonControlMetrics(theme: ButtonTheme, size: IconButtonSize): {
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
minHeight: number;
|
|
21
|
+
iconCellHeight: number;
|
|
22
|
+
paddingVertical: number;
|
|
23
|
+
hasExplicitHeight: boolean;
|
|
19
24
|
};
|
|
20
|
-
/**
|
|
21
|
-
declare function
|
|
25
|
+
/** Apply the metric-safe line height after the token typography styles. */
|
|
26
|
+
declare function getButtonTextStyle(textStyle: TextStyle, labelLineHeight: number): TextStyle;
|
|
22
27
|
//#endregion
|
|
23
|
-
export { getButtonControlMetrics,
|
|
28
|
+
export { getButtonControlMetrics, getButtonTextStyle, getIconButtonControlMetrics, getSafeIconCell };
|
|
24
29
|
//# sourceMappingURL=buttonTheme.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buttonTheme.d.ts","names":[],"sources":["../../../src/components/Button/buttonTheme.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"buttonTheme.d.ts","names":[],"sources":["../../../src/components/Button/buttonTheme.ts"],"mappings":";;;;;KAKK,WAAA;EAEH,UAAA,EAAY,MAAA;AAAA;;iBA4DE,eAAA,CAAgB,QAAA;;iBAiBhB,uBAAA,CACd,KAAA,EAAO,WAAA,EACP,IAAA,EAAM,UAAA;EAEN,SAAA;EACA,eAAA;EACA,cAAA;EACA,eAAA;AAAA;AAPF;AAAA,iBAgCgB,2BAAA,CACd,KAAA,EAAO,WAAA,EACP,IAAA,EAAM,cAAA;EAEN,SAAA;EACA,cAAA;EACA,eAAA;EACA,iBAAA;AAAA;;iBAyBc,kBAAA,CAAmB,SAAA,EAAW,SAAA,EAAW,eAAA,WAA0B,SAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
|
+
import { fontMetrics } from "../../mobile/generated/fontMetrics.js";
|
|
2
3
|
//#region src/components/Button/buttonTheme.ts
|
|
3
4
|
const SHARED_BUTTON_ICONBUTTON_SIZES = new Set([
|
|
4
5
|
"xs",
|
|
@@ -6,6 +7,7 @@ const SHARED_BUTTON_ICONBUTTON_SIZES = new Set([
|
|
|
6
7
|
"md",
|
|
7
8
|
"lg"
|
|
8
9
|
]);
|
|
10
|
+
const UNKNOWN_FONT_LINE_HEIGHT_RATIO = 1.3;
|
|
9
11
|
function buttonSizePath(size, layer) {
|
|
10
12
|
return `button/size/${size}/${layer}/rest`;
|
|
11
13
|
}
|
|
@@ -22,47 +24,71 @@ function getIconSize(iconStyle) {
|
|
|
22
24
|
function getVerticalPadding(rootStyle) {
|
|
23
25
|
return (typeof rootStyle.paddingVertical === "number" ? rootStyle.paddingVertical : void 0) ?? (typeof rootStyle.padding === "number" ? rootStyle.padding : void 0) ?? 0;
|
|
24
26
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
function getMetricHeight(value, unitsPerEm, fontSize) {
|
|
28
|
+
return Math.ceil(Math.max(0, value) / unitsPerEm * fontSize);
|
|
29
|
+
}
|
|
30
|
+
function getSafeLabelLineHeight(textStyle, fallbackFontSize) {
|
|
31
|
+
const fontSize = typeof textStyle.fontSize === "number" ? textStyle.fontSize : fallbackFontSize;
|
|
32
|
+
const tokenLineHeight = typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : fontSize;
|
|
33
|
+
const metrics = typeof textStyle.fontFamily === "string" ? fontMetrics[textStyle.fontFamily] : void 0;
|
|
34
|
+
if (!metrics || metrics.unitsPerEm <= 0) return Math.max(tokenLineHeight, Math.ceil(fontSize * UNKNOWN_FONT_LINE_HEIGHT_RATIO));
|
|
35
|
+
const metricsLineHeight = getMetricHeight(metrics.ascent, metrics.unitsPerEm, fontSize) + getMetricHeight(-metrics.descent, metrics.unitsPerEm, fontSize) + getMetricHeight(metrics.lineGap, metrics.unitsPerEm, fontSize);
|
|
36
|
+
return Math.max(tokenLineHeight, metricsLineHeight);
|
|
29
37
|
}
|
|
30
|
-
/**
|
|
38
|
+
/** Safe line box for the icon font's em square plus any bbox overflow. */
|
|
39
|
+
function getSafeIconCell(fontSize) {
|
|
40
|
+
const metrics = fontMetrics["uds-icons"];
|
|
41
|
+
if (!metrics || metrics.unitsPerEm <= 0) return Math.ceil(fontSize * UNKNOWN_FONT_LINE_HEIGHT_RATIO);
|
|
42
|
+
const overflowAboveEm = Math.max(0, metrics.bbox.maxY - metrics.unitsPerEm);
|
|
43
|
+
const overflowBelowEm = Math.max(0, -metrics.bbox.minY);
|
|
44
|
+
return Math.ceil(fontSize) + getMetricHeight(overflowAboveEm, metrics.unitsPerEm, fontSize) + getMetricHeight(overflowBelowEm, metrics.unitsPerEm, fontSize);
|
|
45
|
+
}
|
|
46
|
+
/** Safe native content metrics while retaining the token-derived target control height. */
|
|
31
47
|
function getButtonControlMetrics(theme, size) {
|
|
32
48
|
const rootStyle = getLayerStyle(theme, buttonSizePath(size, "root"));
|
|
33
49
|
const iconStyle = getLayerStyle(theme, buttonSizePath(size, "icon"));
|
|
34
50
|
const textStyle = getLayerStyle(theme, buttonSizePath(size, "rootText"));
|
|
35
51
|
const paddingVertical = getVerticalPadding(rootStyle);
|
|
36
52
|
const iconSize = getIconSize(iconStyle);
|
|
37
|
-
const
|
|
53
|
+
const fontSize = typeof textStyle.fontSize === "number" ? textStyle.fontSize : iconSize;
|
|
54
|
+
const tokenLineHeight = typeof textStyle.lineHeight === "number" ? textStyle.lineHeight : fontSize;
|
|
55
|
+
const targetContentHeight = Math.max(iconSize, tokenLineHeight);
|
|
56
|
+
const minHeight = Math.ceil(paddingVertical * 2 + targetContentHeight);
|
|
57
|
+
const labelLineHeight = getSafeLabelLineHeight(textStyle, iconSize);
|
|
58
|
+
const iconCellHeight = getSafeIconCell(iconSize);
|
|
38
59
|
return {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
60
|
+
minHeight,
|
|
61
|
+
labelLineHeight,
|
|
62
|
+
iconCellHeight,
|
|
63
|
+
paddingVertical: Math.max(0, (minHeight - Math.max(labelLineHeight, iconCellHeight)) / 2)
|
|
42
64
|
};
|
|
43
65
|
}
|
|
44
|
-
/**
|
|
66
|
+
/** Safe icon cell within the token-derived control size; explicit token height (match-button-height opt-in) wins as the target. */
|
|
45
67
|
function getIconButtonControlMetrics(theme, size) {
|
|
46
68
|
const rootStyle = getLayerStyle(theme, iconButtonSizePath(size, "root"));
|
|
47
|
-
const
|
|
69
|
+
const iconStyle = getLayerStyle(theme, iconButtonSizePath(size, "icon"));
|
|
70
|
+
const iconSize = getIconSize(iconStyle);
|
|
71
|
+
const tokenLineHeight = typeof iconStyle.lineHeight === "number" ? iconStyle.lineHeight : iconSize;
|
|
72
|
+
const paddingVertical = getVerticalPadding(rootStyle);
|
|
48
73
|
const explicitHeight = typeof rootStyle.height === "number" ? rootStyle.height : void 0;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
74
|
+
const hasExplicitHeight = SHARED_BUTTON_ICONBUTTON_SIZES.has(size) && explicitHeight !== void 0;
|
|
75
|
+
const minHeight = hasExplicitHeight ? explicitHeight : Math.ceil(paddingVertical * 2 + Math.max(iconSize, tokenLineHeight));
|
|
76
|
+
const iconCellHeight = getSafeIconCell(iconSize);
|
|
53
77
|
return {
|
|
54
|
-
|
|
55
|
-
|
|
78
|
+
minHeight,
|
|
79
|
+
iconCellHeight,
|
|
80
|
+
paddingVertical: Math.max(0, (minHeight - Math.max(iconSize, iconCellHeight)) / 2),
|
|
81
|
+
hasExplicitHeight
|
|
56
82
|
};
|
|
57
83
|
}
|
|
58
|
-
/**
|
|
59
|
-
function
|
|
84
|
+
/** Apply the metric-safe line height after the token typography styles. */
|
|
85
|
+
function getButtonTextStyle(textStyle, labelLineHeight) {
|
|
60
86
|
return {
|
|
61
87
|
...textStyle,
|
|
62
|
-
lineHeight:
|
|
88
|
+
lineHeight: labelLineHeight
|
|
63
89
|
};
|
|
64
90
|
}
|
|
65
91
|
//#endregion
|
|
66
|
-
export { getButtonControlMetrics,
|
|
92
|
+
export { getButtonControlMetrics, getButtonTextStyle, getIconButtonControlMetrics, getSafeIconCell };
|
|
67
93
|
|
|
68
94
|
//# sourceMappingURL=buttonTheme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buttonTheme.js","names":[],"sources":["../../../src/components/Button/buttonTheme.ts"],"sourcesContent":["import type { ButtonSize, IconButtonSize } from '@yahoo/uds-types';\nimport type { TextStyle, ViewStyle } from 'react-native';\n\ntype ButtonTheme = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n components: Record<string, any>;\n};\n\nconst SHARED_BUTTON_ICONBUTTON_SIZES = new Set<IconButtonSize>(['xs', 'sm', 'md', 'lg']);\n\nfunction buttonSizePath(size: ButtonSize, layer: 'root' | 'icon' | 'rootText'): string {\n return `button/size/${size}/${layer}/rest`;\n}\n\nfunction iconButtonSizePath(size: IconButtonSize, layer: 'root' | 'icon'): string {\n return `iconButton/size/${size}/${layer}/rest`;\n}\n\nfunction getLayerStyle(theme: ButtonTheme, path: string): ViewStyle | TextStyle {\n const style = theme.components[path];\n return style && typeof style === 'object' ? style : {};\n}\n\nfunction getIconSize(iconStyle: TextStyle): number {\n return (\n (typeof iconStyle.fontSize === 'number' ? iconStyle.fontSize : undefined) ??\n (typeof iconStyle.lineHeight === 'number' ? iconStyle.lineHeight : undefined) ??\n 16\n );\n}\n\nfunction getVerticalPadding(rootStyle: ViewStyle): number {\n return (\n (typeof rootStyle.paddingVertical === 'number' ? rootStyle.paddingVertical : undefined) ??\n (typeof rootStyle.padding === 'number' ? rootStyle.padding : undefined) ??\n 0\n );\n}\n\nfunction
|
|
1
|
+
{"version":3,"file":"buttonTheme.js","names":[],"sources":["../../../src/components/Button/buttonTheme.ts"],"sourcesContent":["import type { ButtonSize, IconButtonSize } from '@yahoo/uds-types';\nimport type { TextStyle, ViewStyle } from 'react-native';\n\nimport { fontMetrics } from '../../../generated/fontMetrics';\n\ntype ButtonTheme = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n components: Record<string, any>;\n};\n\nconst SHARED_BUTTON_ICONBUTTON_SIZES = new Set<IconButtonSize>(['xs', 'sm', 'md', 'lg']);\n// Covers common native font boxes (roughly 1.2em) plus pixel-rounding headroom.\nconst UNKNOWN_FONT_LINE_HEIGHT_RATIO = 1.3;\n\nfunction buttonSizePath(size: ButtonSize, layer: 'root' | 'icon' | 'rootText'): string {\n return `button/size/${size}/${layer}/rest`;\n}\n\nfunction iconButtonSizePath(size: IconButtonSize, layer: 'root' | 'icon'): string {\n return `iconButton/size/${size}/${layer}/rest`;\n}\n\nfunction getLayerStyle(theme: ButtonTheme, path: string): ViewStyle | TextStyle {\n const style = theme.components[path];\n return style && typeof style === 'object' ? style : {};\n}\n\nfunction getIconSize(iconStyle: TextStyle): number {\n return (\n (typeof iconStyle.fontSize === 'number' ? iconStyle.fontSize : undefined) ??\n (typeof iconStyle.lineHeight === 'number' ? iconStyle.lineHeight : undefined) ??\n 16\n );\n}\n\nfunction getVerticalPadding(rootStyle: ViewStyle): number {\n return (\n (typeof rootStyle.paddingVertical === 'number' ? rootStyle.paddingVertical : undefined) ??\n (typeof rootStyle.padding === 'number' ? rootStyle.padding : undefined) ??\n 0\n );\n}\n\nfunction getMetricHeight(value: number, unitsPerEm: number, fontSize: number): number {\n return Math.ceil((Math.max(0, value) / unitsPerEm) * fontSize);\n}\n\nfunction getSafeLabelLineHeight(textStyle: TextStyle, fallbackFontSize: number): number {\n const fontSize = typeof textStyle.fontSize === 'number' ? textStyle.fontSize : fallbackFontSize;\n const tokenLineHeight =\n typeof textStyle.lineHeight === 'number' ? textStyle.lineHeight : fontSize;\n const metrics =\n typeof textStyle.fontFamily === 'string' ? fontMetrics[textStyle.fontFamily] : undefined;\n\n if (!metrics || metrics.unitsPerEm <= 0) {\n return Math.max(tokenLineHeight, Math.ceil(fontSize * UNKNOWN_FONT_LINE_HEIGHT_RATIO));\n }\n\n const metricsLineHeight =\n getMetricHeight(metrics.ascent, metrics.unitsPerEm, fontSize) +\n getMetricHeight(-metrics.descent, metrics.unitsPerEm, fontSize) +\n getMetricHeight(metrics.lineGap, metrics.unitsPerEm, fontSize);\n\n return Math.max(tokenLineHeight, metricsLineHeight);\n}\n\n/** Safe line box for the icon font's em square plus any bbox overflow. */\nexport function getSafeIconCell(fontSize: number): number {\n const metrics = fontMetrics['uds-icons'];\n if (!metrics || metrics.unitsPerEm <= 0) {\n return Math.ceil(fontSize * UNKNOWN_FONT_LINE_HEIGHT_RATIO);\n }\n\n const overflowAboveEm = Math.max(0, metrics.bbox.maxY - metrics.unitsPerEm);\n const overflowBelowEm = Math.max(0, -metrics.bbox.minY);\n\n return (\n Math.ceil(fontSize) +\n getMetricHeight(overflowAboveEm, metrics.unitsPerEm, fontSize) +\n getMetricHeight(overflowBelowEm, metrics.unitsPerEm, fontSize)\n );\n}\n\n/** Safe native content metrics while retaining the token-derived target control height. */\nexport function getButtonControlMetrics(\n theme: ButtonTheme,\n size: ButtonSize,\n): {\n minHeight: number;\n labelLineHeight: number;\n iconCellHeight: number;\n paddingVertical: number;\n} {\n const rootStyle = getLayerStyle(theme, buttonSizePath(size, 'root')) as ViewStyle;\n const iconStyle = getLayerStyle(theme, buttonSizePath(size, 'icon')) as TextStyle;\n const textStyle = getLayerStyle(theme, buttonSizePath(size, 'rootText')) as TextStyle;\n const paddingVertical = getVerticalPadding(rootStyle);\n const iconSize = getIconSize(iconStyle);\n const fontSize = typeof textStyle.fontSize === 'number' ? textStyle.fontSize : iconSize;\n const tokenLineHeight =\n typeof textStyle.lineHeight === 'number' ? textStyle.lineHeight : fontSize;\n const targetContentHeight = Math.max(iconSize, tokenLineHeight);\n const minHeight = Math.ceil(paddingVertical * 2 + targetContentHeight);\n const labelLineHeight = getSafeLabelLineHeight(textStyle, iconSize);\n const iconCellHeight = getSafeIconCell(iconSize);\n const safeContentHeight = Math.max(labelLineHeight, iconCellHeight);\n\n return {\n minHeight,\n labelLineHeight,\n iconCellHeight,\n paddingVertical: Math.max(0, (minHeight - safeContentHeight) / 2),\n };\n}\n\n/** Safe icon cell within the token-derived control size; explicit token height (match-button-height opt-in) wins as the target. */\nexport function getIconButtonControlMetrics(\n theme: ButtonTheme,\n size: IconButtonSize,\n): {\n minHeight: number;\n iconCellHeight: number;\n paddingVertical: number;\n hasExplicitHeight: boolean;\n} {\n const rootStyle = getLayerStyle(theme, iconButtonSizePath(size, 'root')) as ViewStyle;\n const iconStyle = getLayerStyle(theme, iconButtonSizePath(size, 'icon')) as TextStyle;\n const iconSize = getIconSize(iconStyle);\n const tokenLineHeight =\n typeof iconStyle.lineHeight === 'number' ? iconStyle.lineHeight : iconSize;\n const paddingVertical = getVerticalPadding(rootStyle);\n const explicitHeight = typeof rootStyle.height === 'number' ? rootStyle.height : undefined;\n const hasExplicitHeight =\n SHARED_BUTTON_ICONBUTTON_SIZES.has(size) && explicitHeight !== undefined;\n const minHeight = hasExplicitHeight\n ? (explicitHeight as number)\n : Math.ceil(paddingVertical * 2 + Math.max(iconSize, tokenLineHeight));\n const iconCellHeight = getSafeIconCell(iconSize);\n\n return {\n minHeight,\n iconCellHeight,\n paddingVertical: Math.max(0, (minHeight - Math.max(iconSize, iconCellHeight)) / 2),\n hasExplicitHeight,\n };\n}\n\n/** Apply the metric-safe line height after the token typography styles. */\nexport function getButtonTextStyle(textStyle: TextStyle, labelLineHeight: number): TextStyle {\n return {\n ...textStyle,\n lineHeight: labelLineHeight,\n };\n}\n"],"mappings":"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"}
|
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
4
4
|
const require_index = require("../motion-tokens/dist/index.cjs");
|
|
5
5
|
const require_motion = require("../motion.cjs");
|
|
6
|
+
const require_components_Button_buttonTheme = require("./Button/buttonTheme.cjs");
|
|
6
7
|
const require_components_IconSlot = require("./IconSlot.cjs");
|
|
7
8
|
const require_components_Text = require("./Text.cjs");
|
|
8
|
-
const require_components_Button_buttonTheme = require("./Button/buttonTheme.cjs");
|
|
9
9
|
const require_components_Pressable = require("./Pressable.cjs");
|
|
10
10
|
let react = require("react");
|
|
11
11
|
let react_native = require("react-native");
|
|
@@ -34,7 +34,7 @@ function interpolateShadowAlpha(shadow, alpha) {
|
|
|
34
34
|
* Matches web Button icon animation: scale 0.7→1, opacity 0→1, width 0→auto
|
|
35
35
|
* Uses staggered animation: opacity waits until halfway through width animation.
|
|
36
36
|
*/
|
|
37
|
-
function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
37
|
+
function AnimatedIconSlot({ children, visible, iconSize, iconCellHeight, gap }) {
|
|
38
38
|
const progress = (0, react_native_reanimated.useDerivedValue)(() => (0, react_native_reanimated.withSpring)(visible ? 1 : 0, require_motion.BUTTON_SPRING_CONFIG), [visible]);
|
|
39
39
|
const animatedStyle = (0, react_native_reanimated.useAnimatedStyle)(() => {
|
|
40
40
|
const totalWidth = iconSize + gap;
|
|
@@ -42,7 +42,9 @@ function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
|
42
42
|
width: (0, react_native_reanimated.interpolate)(progress.value, [0, 1], [0, totalWidth]),
|
|
43
43
|
opacity: (0, react_native_reanimated.interpolate)(progress.value, [.5, 1], [0, 1], "clamp"),
|
|
44
44
|
transform: [{ scale: (0, react_native_reanimated.interpolate)(progress.value, [.5, 1], [.7, 1], "clamp") }],
|
|
45
|
-
overflow: "hidden"
|
|
45
|
+
overflow: "hidden",
|
|
46
|
+
minHeight: iconCellHeight,
|
|
47
|
+
justifyContent: "center"
|
|
46
48
|
};
|
|
47
49
|
});
|
|
48
50
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_reanimated.default.View, {
|
|
@@ -85,7 +87,7 @@ function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
|
85
87
|
const Button = (0, react.memo)(function Button({ variant = "primary", size = "md", iconVariant = "outline", startIcon, endIcon, loading, disabled, width: _width, children, style, accessibilityLabel, accessibilityHint, disableEffects = false, onPressIn, onPressOut, ref, ...props }) {
|
|
86
88
|
const shouldAnimate = !disableEffects;
|
|
87
89
|
const { theme } = (0, react_native_unistyles.useUnistyles)();
|
|
88
|
-
const {
|
|
90
|
+
const { minHeight, labelLineHeight, iconCellHeight, paddingVertical } = (0, react.useMemo)(() => require_components_Button_buttonTheme.getButtonControlMetrics(theme, size), [theme, size]);
|
|
89
91
|
const [pressed, setPressed] = (0, react.useState)(false);
|
|
90
92
|
generated_styles.buttonStyles.useVariants({
|
|
91
93
|
size,
|
|
@@ -118,7 +120,7 @@ const Button = (0, react.memo)(function Button({ variant = "primary", size = "md
|
|
|
118
120
|
const childrenNode = children && ((0, react.isValidElement)(children) ? children : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Text.Text, {
|
|
119
121
|
numberOfLines: 1,
|
|
120
122
|
textAlign: "center",
|
|
121
|
-
style: require_components_Button_buttonTheme.
|
|
123
|
+
style: require_components_Button_buttonTheme.getButtonTextStyle(generated_styles.buttonStyles.text, labelLineHeight),
|
|
122
124
|
children
|
|
123
125
|
}));
|
|
124
126
|
const a11yState = (0, react.useMemo)(() => ({
|
|
@@ -143,6 +145,7 @@ const Button = (0, react.memo)(function Button({ variant = "primary", size = "md
|
|
|
143
145
|
const startContent = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnimatedIconSlot, {
|
|
144
146
|
visible: showLoading || showStartIcon,
|
|
145
147
|
iconSize,
|
|
148
|
+
iconCellHeight,
|
|
146
149
|
gap: buttonGap,
|
|
147
150
|
children: showLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.ActivityIndicator, {
|
|
148
151
|
size: generated_styles.buttonStyles.icon.fontSize,
|
|
@@ -151,28 +154,33 @@ const Button = (0, react.memo)(function Button({ variant = "primary", size = "md
|
|
|
151
154
|
icon: startIcon,
|
|
152
155
|
size: iconSizeToken,
|
|
153
156
|
variant: iconVariant,
|
|
154
|
-
style: generated_styles.buttonStyles.icon
|
|
157
|
+
style: [generated_styles.buttonStyles.icon, { lineHeight: iconCellHeight }]
|
|
155
158
|
})
|
|
156
159
|
});
|
|
157
160
|
const endContent = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnimatedIconSlot, {
|
|
158
161
|
visible: showEndIcon,
|
|
159
162
|
iconSize,
|
|
163
|
+
iconCellHeight,
|
|
160
164
|
gap: buttonGap,
|
|
161
165
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconSlot.IconSlot, {
|
|
162
166
|
icon: endIcon,
|
|
163
167
|
size: iconSizeToken,
|
|
164
168
|
variant: iconVariant,
|
|
165
|
-
style: generated_styles.buttonStyles.icon
|
|
169
|
+
style: [generated_styles.buttonStyles.icon, { lineHeight: iconCellHeight }]
|
|
166
170
|
})
|
|
167
171
|
});
|
|
168
172
|
const rootStyles = (0, react.useMemo)(() => [
|
|
169
173
|
generated_styles.buttonStyles.root,
|
|
170
|
-
{
|
|
174
|
+
{
|
|
175
|
+
minHeight,
|
|
176
|
+
paddingVertical
|
|
177
|
+
},
|
|
171
178
|
animatedStyles,
|
|
172
179
|
typeof style === "function" ? style({ pressed }) : style
|
|
173
180
|
], [
|
|
174
181
|
generated_styles.buttonStyles.root,
|
|
175
|
-
|
|
182
|
+
minHeight,
|
|
183
|
+
paddingVertical,
|
|
176
184
|
animatedStyles,
|
|
177
185
|
style,
|
|
178
186
|
pressed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.d.cts","names":[],"sources":["../../src/components/Button.tsx"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Button.d.cts","names":[],"sources":["../../src/components/Button.tsx"],"mappings":";;;;;;;;;UAqHU,WAAA,SAAoB,IAAA,CAAK,gBAAA;;EAEjC,OAAA,GAAU,iBAAA;EAFF;EAIR,IAAA,GAAO,UAAA;;EAEP,WAAA,GAAc,WAAA;EAJJ;EAMV,SAAA,GAAY,YAAA;EAFE;EAId,OAAA,GAAU,YAAA;EAAA;EAEV,OAAA;EAWU;EATV,QAAA;EAd4B;EAgB5B,QAAA,GAAW,KAAA,CAAM,SAAA;EAhBe;;;;EAqBhC,cAAA;EAjBA;EAmBA,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;;;;;;;AAAI;;;;;;;;;;;;;;;;cAuCV,MAAA,EAAM,OAAA,CAAA,oBAAA,CAAA,WAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.d.ts","names":[],"sources":["../../src/components/Button.tsx"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Button.d.ts","names":[],"sources":["../../src/components/Button.tsx"],"mappings":";;;;;;;;;UAqHU,WAAA,SAAoB,IAAA,CAAK,gBAAA;;EAEjC,OAAA,GAAU,iBAAA;EAFF;EAIR,IAAA,GAAO,UAAA;;EAEP,WAAA,GAAc,WAAA;EAJJ;EAMV,SAAA,GAAY,YAAA;EAFE;EAId,OAAA,GAAU,YAAA;EAAA;EAEV,OAAA;EAWU;EATV,QAAA;EAd4B;EAgB5B,QAAA,GAAW,KAAA,CAAM,SAAA;EAhBe;;;;EAqBhC,cAAA;EAjBA;EAmBA,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;;;;;;;AAAI;;;;;;;;;;;;;;;;cAuCV,MAAA,EAAM,OAAA,CAAA,oBAAA,CAAA,WAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
|
|
2
2
|
import { SCALE_EFFECTS } from "../motion-tokens/dist/index.js";
|
|
3
3
|
import { BUTTON_SPRING_CONFIG } from "../motion.js";
|
|
4
|
+
import { getButtonControlMetrics, getButtonTextStyle } from "./Button/buttonTheme.js";
|
|
4
5
|
import { IconSlot } from "./IconSlot.js";
|
|
5
6
|
import { Text as Text$1 } from "./Text.js";
|
|
6
|
-
import { getButtonControlMetrics, getButtonTextStyleForControlHeight } from "./Button/buttonTheme.js";
|
|
7
7
|
import { AnimatedPressable } from "./Pressable.js";
|
|
8
8
|
import { isValidElement, memo, useCallback, useMemo, useState } from "react";
|
|
9
9
|
import { ActivityIndicator } from "react-native";
|
|
@@ -31,7 +31,7 @@ function interpolateShadowAlpha(shadow, alpha) {
|
|
|
31
31
|
* Matches web Button icon animation: scale 0.7→1, opacity 0→1, width 0→auto
|
|
32
32
|
* Uses staggered animation: opacity waits until halfway through width animation.
|
|
33
33
|
*/
|
|
34
|
-
function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
34
|
+
function AnimatedIconSlot({ children, visible, iconSize, iconCellHeight, gap }) {
|
|
35
35
|
const progress = useDerivedValue(() => withSpring(visible ? 1 : 0, BUTTON_SPRING_CONFIG), [visible]);
|
|
36
36
|
const animatedStyle = useAnimatedStyle(() => {
|
|
37
37
|
const totalWidth = iconSize + gap;
|
|
@@ -39,7 +39,9 @@ function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
|
39
39
|
width: interpolate(progress.value, [0, 1], [0, totalWidth]),
|
|
40
40
|
opacity: interpolate(progress.value, [.5, 1], [0, 1], "clamp"),
|
|
41
41
|
transform: [{ scale: interpolate(progress.value, [.5, 1], [.7, 1], "clamp") }],
|
|
42
|
-
overflow: "hidden"
|
|
42
|
+
overflow: "hidden",
|
|
43
|
+
minHeight: iconCellHeight,
|
|
44
|
+
justifyContent: "center"
|
|
43
45
|
};
|
|
44
46
|
});
|
|
45
47
|
return /* @__PURE__ */ jsx(Animated.View, {
|
|
@@ -82,7 +84,7 @@ function AnimatedIconSlot({ children, visible, iconSize, gap }) {
|
|
|
82
84
|
const Button = memo(function Button({ variant = "primary", size = "md", iconVariant = "outline", startIcon, endIcon, loading, disabled, width: _width, children, style, accessibilityLabel, accessibilityHint, disableEffects = false, onPressIn, onPressOut, ref, ...props }) {
|
|
83
85
|
const shouldAnimate = !disableEffects;
|
|
84
86
|
const { theme } = useUnistyles();
|
|
85
|
-
const {
|
|
87
|
+
const { minHeight, labelLineHeight, iconCellHeight, paddingVertical } = useMemo(() => getButtonControlMetrics(theme, size), [theme, size]);
|
|
86
88
|
const [pressed, setPressed] = useState(false);
|
|
87
89
|
buttonStyles.useVariants({
|
|
88
90
|
size,
|
|
@@ -115,7 +117,7 @@ const Button = memo(function Button({ variant = "primary", size = "md", iconVari
|
|
|
115
117
|
const childrenNode = children && (isValidElement(children) ? children : /* @__PURE__ */ jsx(Text$1, {
|
|
116
118
|
numberOfLines: 1,
|
|
117
119
|
textAlign: "center",
|
|
118
|
-
style:
|
|
120
|
+
style: getButtonTextStyle(buttonStyles.text, labelLineHeight),
|
|
119
121
|
children
|
|
120
122
|
}));
|
|
121
123
|
const a11yState = useMemo(() => ({
|
|
@@ -140,6 +142,7 @@ const Button = memo(function Button({ variant = "primary", size = "md", iconVari
|
|
|
140
142
|
const startContent = /* @__PURE__ */ jsx(AnimatedIconSlot, {
|
|
141
143
|
visible: showLoading || showStartIcon,
|
|
142
144
|
iconSize,
|
|
145
|
+
iconCellHeight,
|
|
143
146
|
gap: buttonGap,
|
|
144
147
|
children: showLoading ? /* @__PURE__ */ jsx(ActivityIndicator, {
|
|
145
148
|
size: buttonStyles.icon.fontSize,
|
|
@@ -148,28 +151,33 @@ const Button = memo(function Button({ variant = "primary", size = "md", iconVari
|
|
|
148
151
|
icon: startIcon,
|
|
149
152
|
size: iconSizeToken,
|
|
150
153
|
variant: iconVariant,
|
|
151
|
-
style: buttonStyles.icon
|
|
154
|
+
style: [buttonStyles.icon, { lineHeight: iconCellHeight }]
|
|
152
155
|
})
|
|
153
156
|
});
|
|
154
157
|
const endContent = /* @__PURE__ */ jsx(AnimatedIconSlot, {
|
|
155
158
|
visible: showEndIcon,
|
|
156
159
|
iconSize,
|
|
160
|
+
iconCellHeight,
|
|
157
161
|
gap: buttonGap,
|
|
158
162
|
children: /* @__PURE__ */ jsx(IconSlot, {
|
|
159
163
|
icon: endIcon,
|
|
160
164
|
size: iconSizeToken,
|
|
161
165
|
variant: iconVariant,
|
|
162
|
-
style: buttonStyles.icon
|
|
166
|
+
style: [buttonStyles.icon, { lineHeight: iconCellHeight }]
|
|
163
167
|
})
|
|
164
168
|
});
|
|
165
169
|
const rootStyles = useMemo(() => [
|
|
166
170
|
buttonStyles.root,
|
|
167
|
-
{
|
|
171
|
+
{
|
|
172
|
+
minHeight,
|
|
173
|
+
paddingVertical
|
|
174
|
+
},
|
|
168
175
|
animatedStyles,
|
|
169
176
|
typeof style === "function" ? style({ pressed }) : style
|
|
170
177
|
], [
|
|
171
178
|
buttonStyles.root,
|
|
172
|
-
|
|
179
|
+
minHeight,
|
|
180
|
+
paddingVertical,
|
|
173
181
|
animatedStyles,
|
|
174
182
|
style,
|
|
175
183
|
pressed
|