@xsolla/xui-button 0.216.1 → 0.218.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 -3
- package/native/index.d.ts +25 -3
- package/native/index.js +10 -33
- package/native/index.js.map +1 -1
- package/native/index.mjs +10 -33
- package/native/index.mjs.map +1 -1
- package/package.json +4 -4
- package/web/index.d.mts +25 -3
- package/web/index.d.ts +25 -3
- package/web/index.js +10 -33
- package/web/index.js.map +1 -1
- package/web/index.mjs +10 -33
- package/web/index.mjs.map +1 -1
package/web/index.d.mts
CHANGED
|
@@ -183,7 +183,13 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
183
183
|
variant?: "brand" | "primary" | "secondary" | "tertiary" | "brandExtra" | "inverse";
|
|
184
184
|
/** Size of the button */
|
|
185
185
|
size?: "xl" | "lg" | "md" | "sm" | "xs";
|
|
186
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* Whether to show background fill.
|
|
188
|
+
*
|
|
189
|
+
* This also drives the button's frame padding: a filled button is padded per
|
|
190
|
+
* size ({@link BACKGROUND_PADDING}), while an unfilled one renders flush so
|
|
191
|
+
* it sits inline with surrounding text (XUITSD-86).
|
|
192
|
+
*/
|
|
187
193
|
background?: boolean;
|
|
188
194
|
/**
|
|
189
195
|
* Whether to show the hover/press background color.
|
|
@@ -198,6 +204,9 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
198
204
|
* class or `style` prop a consumer passes, so this prop is the supported way
|
|
199
205
|
* to render a zero-padding FlexButton (e.g. an inline text action).
|
|
200
206
|
*
|
|
207
|
+
* Only meaningful together with `background` — an unfilled FlexButton already
|
|
208
|
+
* renders flush at every size, so `noPadding` is a no-op there (XUITSD-86).
|
|
209
|
+
*
|
|
201
210
|
* Icon-only buttons keep their square dimensions when `noPadding` is set —
|
|
202
211
|
* only the inner padding is removed.
|
|
203
212
|
* @default false
|
|
@@ -239,12 +248,22 @@ declare const getFlexButtonBoxSize: (size?: NonNullable<FlexButtonProps["size"]>
|
|
|
239
248
|
*
|
|
240
249
|
* Renders as a semantic `<button>` element with full ARIA support.
|
|
241
250
|
*
|
|
251
|
+
* ## Frame padding
|
|
252
|
+
*
|
|
253
|
+
* Padding follows the `background` prop. A filled button (`background`) is
|
|
254
|
+
* padded per size — 2px at `xs`/`sm`/`md`, 4px at `lg`/`xl` — while an unfilled
|
|
255
|
+
* one renders flush on all four sides so it flows inline with surrounding text.
|
|
256
|
+
* `noPadding` strips the padding from a filled button; on an unfilled one there
|
|
257
|
+
* is nothing left to strip (XUITSD-86).
|
|
258
|
+
*
|
|
242
259
|
* ## Icon-only buttons
|
|
243
260
|
*
|
|
244
261
|
* A FlexButton is icon-only when it has no text label and an icon is supplied
|
|
245
262
|
* either as `children` or via `iconLeft`/`iconRight`. Icon-only buttons render
|
|
246
263
|
* as a square whose side equals `theme.sizing.flexButton(size).height`, so they
|
|
247
|
-
* line up with the Modal header icon slots (36x36 at `size="xl"`).
|
|
264
|
+
* line up with the Modal header icon slots (36x36 at `size="xl"`). The square is
|
|
265
|
+
* independent of the padding above, so an unfilled icon-only button keeps its
|
|
266
|
+
* hit area and simply centres the icon inside it.
|
|
248
267
|
*
|
|
249
268
|
* ```tsx
|
|
250
269
|
* <FlexButton variant="secondary" size="xl" aria-label="Go back">
|
|
@@ -257,7 +276,10 @@ declare const getFlexButtonBoxSize: (size?: NonNullable<FlexButtonProps["size"]>
|
|
|
257
276
|
* - **Semantic HTML**: Renders as a native `<button>` element
|
|
258
277
|
* - **Keyboard Navigation**: Focusable via Tab, activated with Enter or Space
|
|
259
278
|
* - **ARIA States**: Properly announces disabled and loading states
|
|
260
|
-
* - **Focus Indicator**:
|
|
279
|
+
* - **Focus Indicator**: The browser's native `:focus-visible` ring. The design
|
|
280
|
+
* system specifies no focus treatment for FlexButton (XUITSD-61), so the
|
|
281
|
+
* component paints none of its own and does not suppress the UA outline —
|
|
282
|
+
* which keeps a keyboard-only indicator without drawing a ring on click.
|
|
261
283
|
* - **Screen Reader Support**: Announces button label, state, and any associated descriptions
|
|
262
284
|
*/
|
|
263
285
|
declare const FlexButton: React.ForwardRefExoticComponent<FlexButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
package/web/index.d.ts
CHANGED
|
@@ -183,7 +183,13 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
183
183
|
variant?: "brand" | "primary" | "secondary" | "tertiary" | "brandExtra" | "inverse";
|
|
184
184
|
/** Size of the button */
|
|
185
185
|
size?: "xl" | "lg" | "md" | "sm" | "xs";
|
|
186
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* Whether to show background fill.
|
|
188
|
+
*
|
|
189
|
+
* This also drives the button's frame padding: a filled button is padded per
|
|
190
|
+
* size ({@link BACKGROUND_PADDING}), while an unfilled one renders flush so
|
|
191
|
+
* it sits inline with surrounding text (XUITSD-86).
|
|
192
|
+
*/
|
|
187
193
|
background?: boolean;
|
|
188
194
|
/**
|
|
189
195
|
* Whether to show the hover/press background color.
|
|
@@ -198,6 +204,9 @@ interface FlexButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElem
|
|
|
198
204
|
* class or `style` prop a consumer passes, so this prop is the supported way
|
|
199
205
|
* to render a zero-padding FlexButton (e.g. an inline text action).
|
|
200
206
|
*
|
|
207
|
+
* Only meaningful together with `background` — an unfilled FlexButton already
|
|
208
|
+
* renders flush at every size, so `noPadding` is a no-op there (XUITSD-86).
|
|
209
|
+
*
|
|
201
210
|
* Icon-only buttons keep their square dimensions when `noPadding` is set —
|
|
202
211
|
* only the inner padding is removed.
|
|
203
212
|
* @default false
|
|
@@ -239,12 +248,22 @@ declare const getFlexButtonBoxSize: (size?: NonNullable<FlexButtonProps["size"]>
|
|
|
239
248
|
*
|
|
240
249
|
* Renders as a semantic `<button>` element with full ARIA support.
|
|
241
250
|
*
|
|
251
|
+
* ## Frame padding
|
|
252
|
+
*
|
|
253
|
+
* Padding follows the `background` prop. A filled button (`background`) is
|
|
254
|
+
* padded per size — 2px at `xs`/`sm`/`md`, 4px at `lg`/`xl` — while an unfilled
|
|
255
|
+
* one renders flush on all four sides so it flows inline with surrounding text.
|
|
256
|
+
* `noPadding` strips the padding from a filled button; on an unfilled one there
|
|
257
|
+
* is nothing left to strip (XUITSD-86).
|
|
258
|
+
*
|
|
242
259
|
* ## Icon-only buttons
|
|
243
260
|
*
|
|
244
261
|
* A FlexButton is icon-only when it has no text label and an icon is supplied
|
|
245
262
|
* either as `children` or via `iconLeft`/`iconRight`. Icon-only buttons render
|
|
246
263
|
* as a square whose side equals `theme.sizing.flexButton(size).height`, so they
|
|
247
|
-
* line up with the Modal header icon slots (36x36 at `size="xl"`).
|
|
264
|
+
* line up with the Modal header icon slots (36x36 at `size="xl"`). The square is
|
|
265
|
+
* independent of the padding above, so an unfilled icon-only button keeps its
|
|
266
|
+
* hit area and simply centres the icon inside it.
|
|
248
267
|
*
|
|
249
268
|
* ```tsx
|
|
250
269
|
* <FlexButton variant="secondary" size="xl" aria-label="Go back">
|
|
@@ -257,7 +276,10 @@ declare const getFlexButtonBoxSize: (size?: NonNullable<FlexButtonProps["size"]>
|
|
|
257
276
|
* - **Semantic HTML**: Renders as a native `<button>` element
|
|
258
277
|
* - **Keyboard Navigation**: Focusable via Tab, activated with Enter or Space
|
|
259
278
|
* - **ARIA States**: Properly announces disabled and loading states
|
|
260
|
-
* - **Focus Indicator**:
|
|
279
|
+
* - **Focus Indicator**: The browser's native `:focus-visible` ring. The design
|
|
280
|
+
* system specifies no focus treatment for FlexButton (XUITSD-61), so the
|
|
281
|
+
* component paints none of its own and does not suppress the UA outline —
|
|
282
|
+
* which keeps a keyboard-only indicator without drawing a ring on click.
|
|
261
283
|
* - **Screen Reader Support**: Announces button label, state, and any associated descriptions
|
|
262
284
|
*/
|
|
263
285
|
declare const FlexButton: React.ForwardRefExoticComponent<FlexButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
package/web/index.js
CHANGED
|
@@ -932,7 +932,13 @@ var SPINNER_SIZES = {
|
|
|
932
932
|
lg: 18,
|
|
933
933
|
xl: 20
|
|
934
934
|
};
|
|
935
|
-
var
|
|
935
|
+
var BACKGROUND_PADDING = {
|
|
936
|
+
xs: 2,
|
|
937
|
+
sm: 2,
|
|
938
|
+
md: 2,
|
|
939
|
+
lg: 4,
|
|
940
|
+
xl: 4
|
|
941
|
+
};
|
|
936
942
|
var hasVisibleLabel = (node) => {
|
|
937
943
|
if (node == null || node === false || node === true) return false;
|
|
938
944
|
if (typeof node === "string") return node.trim().length > 0;
|
|
@@ -1009,7 +1015,6 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1009
1015
|
}, ref) => {
|
|
1010
1016
|
const { theme } = (0, import_xui_core3.useResolvedTheme)({ themeMode, themeProductContext });
|
|
1011
1017
|
const [state, setState] = (0, import_react5.useState)("default");
|
|
1012
|
-
const [isFocused, setIsFocused] = (0, import_react5.useState)(false);
|
|
1013
1018
|
const isMouseOverRef = (0, import_react5.useRef)(false);
|
|
1014
1019
|
const isDisabled = disabled || loading;
|
|
1015
1020
|
const getVariantColors = (currentState) => {
|
|
@@ -1108,18 +1113,6 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1108
1113
|
};
|
|
1109
1114
|
}
|
|
1110
1115
|
};
|
|
1111
|
-
const getFocusRingColor = () => {
|
|
1112
|
-
switch (variant) {
|
|
1113
|
-
case "brand":
|
|
1114
|
-
return theme.colors.overlay.brand;
|
|
1115
|
-
case "brandExtra":
|
|
1116
|
-
return theme.colors.overlay.brandExtra;
|
|
1117
|
-
case "inverse":
|
|
1118
|
-
return "rgba(255, 255, 255, 0.3)";
|
|
1119
|
-
default:
|
|
1120
|
-
return theme.colors.overlay.mono;
|
|
1121
|
-
}
|
|
1122
|
-
};
|
|
1123
1116
|
const getSpinnerColor = () => {
|
|
1124
1117
|
switch (variant) {
|
|
1125
1118
|
case "brand":
|
|
@@ -1139,13 +1132,13 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1139
1132
|
}
|
|
1140
1133
|
};
|
|
1141
1134
|
const colors = getVariantColors(state);
|
|
1142
|
-
const focusRingColor = getFocusRingColor();
|
|
1143
1135
|
const spinnerColor = getSpinnerColor();
|
|
1144
1136
|
const iconSize = ICON_SIZES[size];
|
|
1145
1137
|
const spinnerSize = SPINNER_SIZES[size];
|
|
1146
1138
|
const fontSize = FONT_SIZES[size];
|
|
1147
1139
|
const borderRadius = BORDER_RADIUS[size];
|
|
1148
1140
|
const lineHeight = LINE_HEIGHTS[size];
|
|
1141
|
+
const framePadding = background ? BACKGROUND_PADDING[size] : 0;
|
|
1149
1142
|
const showTextLabel = hasVisibleLabel(children);
|
|
1150
1143
|
const hasIconChildren = !showTextLabel && hasRenderableContent(children);
|
|
1151
1144
|
const isIconOnly = !loading && !showTextLabel && Boolean(iconLeft || iconRight || hasIconChildren);
|
|
@@ -1172,14 +1165,6 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1172
1165
|
setState(isMouseOverRef.current ? "hover" : "default");
|
|
1173
1166
|
}
|
|
1174
1167
|
};
|
|
1175
|
-
const handleFocus = () => {
|
|
1176
|
-
if (!isDisabled) {
|
|
1177
|
-
setIsFocused(true);
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
const handleBlur = () => {
|
|
1181
|
-
setIsFocused(false);
|
|
1182
|
-
};
|
|
1183
1168
|
const handleClick = (event) => {
|
|
1184
1169
|
if (isDisabled) return;
|
|
1185
1170
|
if (onPress) {
|
|
@@ -1207,18 +1192,13 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1207
1192
|
}
|
|
1208
1193
|
};
|
|
1209
1194
|
const borderShadow = colors.border ? `inset 0 0 0 1px ${colors.border}` : void 0;
|
|
1210
|
-
const focusShadow = isFocused && !isDisabled ? `0 0 0 2px ${focusRingColor}` : void 0;
|
|
1211
|
-
const boxShadows = [];
|
|
1212
|
-
if (borderShadow) boxShadows.push(borderShadow);
|
|
1213
|
-
if (focusShadow) boxShadows.push(focusShadow);
|
|
1214
|
-
const combinedBoxShadow = boxShadows.length > 0 ? boxShadows.join(", ") : "none";
|
|
1215
1195
|
const buttonStyle = {
|
|
1216
1196
|
display: "inline-flex",
|
|
1217
1197
|
alignItems: "center",
|
|
1218
1198
|
justifyContent: "center",
|
|
1219
1199
|
gap: isIconOnly ? 0 : "2px",
|
|
1220
1200
|
boxSizing: "border-box",
|
|
1221
|
-
padding: noPadding ? "0px" : `${
|
|
1201
|
+
padding: noPadding ? "0px" : `${framePadding}px`,
|
|
1222
1202
|
backgroundColor: loading ? "transparent" : colors.bg,
|
|
1223
1203
|
color: colors.text,
|
|
1224
1204
|
border: "none",
|
|
@@ -1230,8 +1210,7 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1230
1210
|
lineHeight: isIconOnly ? 0 : lineHeight,
|
|
1231
1211
|
fontFamily: "inherit",
|
|
1232
1212
|
transition: "background-color 100ms ease-in-out, color 100ms ease-in-out, box-shadow 100ms ease-in-out",
|
|
1233
|
-
|
|
1234
|
-
boxShadow: combinedBoxShadow,
|
|
1213
|
+
boxShadow: borderShadow ?? "none",
|
|
1235
1214
|
...isIconOnly && {
|
|
1236
1215
|
width: iconOnlyHitArea,
|
|
1237
1216
|
height: iconOnlyHitArea,
|
|
@@ -1274,8 +1253,6 @@ var FlexButton = (0, import_react5.forwardRef)(
|
|
|
1274
1253
|
onMouseUp: handleMouseUp,
|
|
1275
1254
|
onKeyDown: handleKeyDown,
|
|
1276
1255
|
onKeyUp: handleKeyUp,
|
|
1277
|
-
onFocus: handleFocus,
|
|
1278
|
-
onBlur: handleBlur,
|
|
1279
1256
|
"aria-label": computedAriaLabel,
|
|
1280
1257
|
"aria-busy": loading || void 0,
|
|
1281
1258
|
"aria-disabled": isDisabled || void 0,
|