@xsolla/xui-button 0.190.0 → 0.192.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/native/index.d.mts +25 -2
- package/native/index.d.ts +25 -2
- package/native/index.js +43 -7
- package/native/index.js.map +1 -1
- package/native/index.mjs +43 -7
- package/native/index.mjs.map +1 -1
- package/package.json +4 -4
- package/web/index.d.mts +25 -2
- package/web/index.d.ts +25 -2
- package/web/index.js +43 -7
- package/web/index.js.map +1 -1
- package/web/index.mjs +43 -7
- package/web/index.mjs.map +1 -1
package/native/index.d.mts
CHANGED
|
@@ -170,8 +170,15 @@ interface IconButtonProps extends ThemeOverrideProps {
|
|
|
170
170
|
declare const IconButton: React.FC<IconButtonProps>;
|
|
171
171
|
|
|
172
172
|
interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
|
|
173
|
-
/**
|
|
174
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Button label. Omit for icon-only buttons (provide `aria-label`).
|
|
175
|
+
*
|
|
176
|
+
* An icon may also be passed directly as `children` instead of via
|
|
177
|
+
* `iconLeft`/`iconRight`. When `children` carries no text, the button is
|
|
178
|
+
* treated as icon-only and renders as a square sized from the design-system
|
|
179
|
+
* height token for `size`.
|
|
180
|
+
*/
|
|
181
|
+
children?: ReactNode;
|
|
175
182
|
/** Visual variant of the button */
|
|
176
183
|
variant?: "brand" | "primary" | "secondary" | "tertiary" | "brandExtra" | "inverse";
|
|
177
184
|
/** Size of the button */
|
|
@@ -190,6 +197,9 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
190
197
|
* The component applies padding via an inline style, which overrides any CSS
|
|
191
198
|
* class or `style` prop a consumer passes, so this prop is the supported way
|
|
192
199
|
* to render a zero-padding FlexButton (e.g. an inline text action).
|
|
200
|
+
*
|
|
201
|
+
* Icon-only buttons keep their square dimensions when `noPadding` is set —
|
|
202
|
+
* only the inner padding is removed.
|
|
193
203
|
* @default false
|
|
194
204
|
*/
|
|
195
205
|
noPadding?: boolean;
|
|
@@ -224,6 +234,19 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
224
234
|
*
|
|
225
235
|
* Renders as a semantic `<button>` element with full ARIA support.
|
|
226
236
|
*
|
|
237
|
+
* ## Icon-only buttons
|
|
238
|
+
*
|
|
239
|
+
* A FlexButton is icon-only when it has no text label and an icon is supplied
|
|
240
|
+
* either as `children` or via `iconLeft`/`iconRight`. Icon-only buttons render
|
|
241
|
+
* as a square whose side equals `theme.sizing.flexButton(size).height`, so they
|
|
242
|
+
* line up with the Modal header icon slots (36x36 at `size="xl"`).
|
|
243
|
+
*
|
|
244
|
+
* ```tsx
|
|
245
|
+
* <FlexButton variant="secondary" size="xl" aria-label="Go back">
|
|
246
|
+
* <BackwardAlt variant="line" />
|
|
247
|
+
* </FlexButton>
|
|
248
|
+
* ```
|
|
249
|
+
*
|
|
227
250
|
* ## Accessibility Features
|
|
228
251
|
*
|
|
229
252
|
* - **Semantic HTML**: Renders as a native `<button>` element
|
package/native/index.d.ts
CHANGED
|
@@ -170,8 +170,15 @@ interface IconButtonProps extends ThemeOverrideProps {
|
|
|
170
170
|
declare const IconButton: React.FC<IconButtonProps>;
|
|
171
171
|
|
|
172
172
|
interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
|
|
173
|
-
/**
|
|
174
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Button label. Omit for icon-only buttons (provide `aria-label`).
|
|
175
|
+
*
|
|
176
|
+
* An icon may also be passed directly as `children` instead of via
|
|
177
|
+
* `iconLeft`/`iconRight`. When `children` carries no text, the button is
|
|
178
|
+
* treated as icon-only and renders as a square sized from the design-system
|
|
179
|
+
* height token for `size`.
|
|
180
|
+
*/
|
|
181
|
+
children?: ReactNode;
|
|
175
182
|
/** Visual variant of the button */
|
|
176
183
|
variant?: "brand" | "primary" | "secondary" | "tertiary" | "brandExtra" | "inverse";
|
|
177
184
|
/** Size of the button */
|
|
@@ -190,6 +197,9 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
190
197
|
* The component applies padding via an inline style, which overrides any CSS
|
|
191
198
|
* class or `style` prop a consumer passes, so this prop is the supported way
|
|
192
199
|
* to render a zero-padding FlexButton (e.g. an inline text action).
|
|
200
|
+
*
|
|
201
|
+
* Icon-only buttons keep their square dimensions when `noPadding` is set —
|
|
202
|
+
* only the inner padding is removed.
|
|
193
203
|
* @default false
|
|
194
204
|
*/
|
|
195
205
|
noPadding?: boolean;
|
|
@@ -224,6 +234,19 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
224
234
|
*
|
|
225
235
|
* Renders as a semantic `<button>` element with full ARIA support.
|
|
226
236
|
*
|
|
237
|
+
* ## Icon-only buttons
|
|
238
|
+
*
|
|
239
|
+
* A FlexButton is icon-only when it has no text label and an icon is supplied
|
|
240
|
+
* either as `children` or via `iconLeft`/`iconRight`. Icon-only buttons render
|
|
241
|
+
* as a square whose side equals `theme.sizing.flexButton(size).height`, so they
|
|
242
|
+
* line up with the Modal header icon slots (36x36 at `size="xl"`).
|
|
243
|
+
*
|
|
244
|
+
* ```tsx
|
|
245
|
+
* <FlexButton variant="secondary" size="xl" aria-label="Go back">
|
|
246
|
+
* <BackwardAlt variant="line" />
|
|
247
|
+
* </FlexButton>
|
|
248
|
+
* ```
|
|
249
|
+
*
|
|
227
250
|
* ## Accessibility Features
|
|
228
251
|
*
|
|
229
252
|
* - **Semantic HTML**: Renders as a native `<button>` element
|
package/native/index.js
CHANGED
|
@@ -808,9 +808,27 @@ var IconButton = ({
|
|
|
808
808
|
IconButton.displayName = "IconButton";
|
|
809
809
|
|
|
810
810
|
// src/FlexButton.tsx
|
|
811
|
-
var import_react4 = require("react");
|
|
811
|
+
var import_react4 = __toESM(require("react"));
|
|
812
812
|
var import_xui_core3 = require("@xsolla/xui-core");
|
|
813
813
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
814
|
+
var FLEX_BUTTON_PADDING = 4;
|
|
815
|
+
var hasVisibleLabel = (node) => {
|
|
816
|
+
if (node == null || node === false || node === true) return false;
|
|
817
|
+
if (typeof node === "string") return node.trim().length > 0;
|
|
818
|
+
if (typeof node === "number") return true;
|
|
819
|
+
if (Array.isArray(node)) return node.some(hasVisibleLabel);
|
|
820
|
+
if (import_react4.default.isValidElement(node)) {
|
|
821
|
+
const { children: elementChildren } = node.props ?? {};
|
|
822
|
+
return hasVisibleLabel(elementChildren);
|
|
823
|
+
}
|
|
824
|
+
return true;
|
|
825
|
+
};
|
|
826
|
+
var hasRenderableContent = (node) => {
|
|
827
|
+
if (node == null || node === false || node === true) return false;
|
|
828
|
+
if (typeof node === "string") return node.trim().length > 0;
|
|
829
|
+
if (Array.isArray(node)) return node.some(hasRenderableContent);
|
|
830
|
+
return true;
|
|
831
|
+
};
|
|
814
832
|
var ICON_SIZES = {
|
|
815
833
|
xs: 12,
|
|
816
834
|
sm: 14,
|
|
@@ -1010,6 +1028,10 @@ var FlexButton = ({
|
|
|
1010
1028
|
const fontSize = FONT_SIZES[size];
|
|
1011
1029
|
const borderRadius = BORDER_RADIUS[size];
|
|
1012
1030
|
const lineHeight = LINE_HEIGHTS[size];
|
|
1031
|
+
const showTextLabel = hasVisibleLabel(children);
|
|
1032
|
+
const hasIconChildren = !showTextLabel && hasRenderableContent(children);
|
|
1033
|
+
const isIconOnly = !loading && !showTextLabel && Boolean(iconLeft || iconRight || hasIconChildren);
|
|
1034
|
+
const iconOnlyHitArea = theme.sizing.flexButton(size).height;
|
|
1013
1035
|
const handleMouseEnter = () => {
|
|
1014
1036
|
if (!isDisabled) {
|
|
1015
1037
|
isMouseOverRef.current = true;
|
|
@@ -1076,8 +1098,9 @@ var FlexButton = ({
|
|
|
1076
1098
|
display: "inline-flex",
|
|
1077
1099
|
alignItems: "center",
|
|
1078
1100
|
justifyContent: "center",
|
|
1079
|
-
gap: "2px",
|
|
1080
|
-
|
|
1101
|
+
gap: isIconOnly ? 0 : "2px",
|
|
1102
|
+
boxSizing: "border-box",
|
|
1103
|
+
padding: noPadding ? "0px" : `${FLEX_BUTTON_PADDING}px`,
|
|
1081
1104
|
backgroundColor: loading ? "transparent" : colors.bg,
|
|
1082
1105
|
color: colors.text,
|
|
1083
1106
|
border: "none",
|
|
@@ -1086,18 +1109,30 @@ var FlexButton = ({
|
|
|
1086
1109
|
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
1087
1110
|
fontSize: `${fontSize}px`,
|
|
1088
1111
|
fontWeight: 500,
|
|
1089
|
-
lineHeight,
|
|
1112
|
+
lineHeight: isIconOnly ? 0 : lineHeight,
|
|
1090
1113
|
fontFamily: "inherit",
|
|
1091
1114
|
transition: "background-color 100ms ease-in-out, color 100ms ease-in-out, box-shadow 100ms ease-in-out",
|
|
1092
1115
|
outline: "none",
|
|
1093
1116
|
boxShadow: combinedBoxShadow,
|
|
1094
|
-
opacity: isDisabled && !loading ? 0.6 : 1
|
|
1117
|
+
opacity: isDisabled && !loading ? 0.6 : 1,
|
|
1118
|
+
...isIconOnly && {
|
|
1119
|
+
width: iconOnlyHitArea,
|
|
1120
|
+
height: iconOnlyHitArea,
|
|
1121
|
+
minWidth: iconOnlyHitArea,
|
|
1122
|
+
minHeight: iconOnlyHitArea,
|
|
1123
|
+
flexShrink: 0
|
|
1124
|
+
}
|
|
1095
1125
|
};
|
|
1096
1126
|
const contentStyle = {
|
|
1097
1127
|
display: "flex",
|
|
1098
1128
|
alignItems: "center",
|
|
1099
1129
|
justifyContent: "center",
|
|
1100
|
-
gap: "2px"
|
|
1130
|
+
gap: isIconOnly ? 0 : "2px",
|
|
1131
|
+
...isIconOnly && {
|
|
1132
|
+
width: "100%",
|
|
1133
|
+
height: "100%",
|
|
1134
|
+
lineHeight: 0
|
|
1135
|
+
}
|
|
1101
1136
|
};
|
|
1102
1137
|
const spinnerStyle = {
|
|
1103
1138
|
display: "flex",
|
|
@@ -1136,7 +1171,8 @@ var FlexButton = ({
|
|
|
1136
1171
|
"data-testid": testID || "flex-button",
|
|
1137
1172
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: contentStyle, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: spinnerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spinner, { size: spinnerSize, color: spinnerColor }) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1138
1173
|
iconLeft && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { size: iconSize, color: colors.text, children: iconLeft }),
|
|
1139
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children }),
|
|
1174
|
+
showTextLabel && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children }),
|
|
1175
|
+
hasIconChildren && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { size: iconSize, color: colors.text, children }),
|
|
1140
1176
|
iconRight && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { size: iconSize, color: colors.text, children: iconRight })
|
|
1141
1177
|
] }) })
|
|
1142
1178
|
}
|