@xsolla/xui-spinner 0.131.0 → 0.133.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsolla/xui-spinner",
3
- "version": "0.131.0",
3
+ "version": "0.133.0",
4
4
  "main": "./web/index.js",
5
5
  "module": "./web/index.mjs",
6
6
  "types": "./web/index.d.ts",
@@ -10,8 +10,8 @@
10
10
  "build:native": "PLATFORM=native tsup"
11
11
  },
12
12
  "dependencies": {
13
- "@xsolla/xui-core": "0.131.0",
14
- "@xsolla/xui-primitives-core": "0.131.0"
13
+ "@xsolla/xui-core": "0.133.0",
14
+ "@xsolla/xui-primitives-core": "0.133.0"
15
15
  },
16
16
  "peerDependencies": {
17
17
  "react": ">=16.8.0",
package/web/index.js CHANGED
@@ -34,6 +34,110 @@ __export(index_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
+ // ../primitives-web/src/filterDOMProps.ts
38
+ var import_react = __toESM(require("react"));
39
+ var NON_HTML_PROPS = /* @__PURE__ */ new Set([
40
+ // BoxProps — layout & styling
41
+ "backgroundColor",
42
+ "borderColor",
43
+ "borderWidth",
44
+ "borderBottomWidth",
45
+ "borderBottomColor",
46
+ "borderTopWidth",
47
+ "borderTopColor",
48
+ "borderLeftWidth",
49
+ "borderLeftColor",
50
+ "borderRightWidth",
51
+ "borderRightColor",
52
+ "borderRadius",
53
+ "borderStyle",
54
+ "flexDirection",
55
+ "flexWrap",
56
+ "alignItems",
57
+ "justifyContent",
58
+ "alignSelf",
59
+ "flex",
60
+ "flexShrink",
61
+ "gap",
62
+ "position",
63
+ "top",
64
+ "bottom",
65
+ "left",
66
+ "right",
67
+ "outline",
68
+ "overflow",
69
+ "overflowX",
70
+ "overflowY",
71
+ "zIndex",
72
+ "cursor",
73
+ "padding",
74
+ "paddingHorizontal",
75
+ "paddingVertical",
76
+ "paddingTop",
77
+ "paddingBottom",
78
+ "paddingLeft",
79
+ "paddingRight",
80
+ "margin",
81
+ "marginTop",
82
+ "marginBottom",
83
+ "marginLeft",
84
+ "marginRight",
85
+ "minWidth",
86
+ "minHeight",
87
+ "maxWidth",
88
+ "maxHeight",
89
+ "hoverStyle",
90
+ "pressStyle",
91
+ "focusStyle",
92
+ "outlineColor",
93
+ "outlineWidth",
94
+ "outlineOffset",
95
+ "outlineStyle",
96
+ // BoxProps — RN-only
97
+ "onPress",
98
+ "onLayout",
99
+ "onMoveShouldSetResponder",
100
+ "onResponderGrant",
101
+ "onResponderMove",
102
+ "onResponderRelease",
103
+ "onResponderTerminate",
104
+ "testID",
105
+ // Box — custom element type
106
+ "elementType",
107
+ // TextProps
108
+ "fontSize",
109
+ "fontWeight",
110
+ "fontFamily",
111
+ "lineHeight",
112
+ "whiteSpace",
113
+ "textAlign",
114
+ "textDecoration",
115
+ "numberOfLines",
116
+ "letterSpacing",
117
+ "textTransform",
118
+ // SpinnerProps
119
+ "strokeWidth",
120
+ // DividerProps
121
+ "vertical",
122
+ "dashStroke"
123
+ ]);
124
+ function createFilteredElement(defaultTag) {
125
+ const Component = import_react.default.forwardRef(
126
+ ({ children, elementType, ...props }, ref) => {
127
+ const Tag = elementType || defaultTag;
128
+ const htmlProps = {};
129
+ for (const key of Object.keys(props)) {
130
+ if (!NON_HTML_PROPS.has(key)) {
131
+ htmlProps[key] = props[key];
132
+ }
133
+ }
134
+ return import_react.default.createElement(Tag, { ref, ...htmlProps }, children);
135
+ }
136
+ );
137
+ Component.displayName = `Filtered(${defaultTag})`;
138
+ return Component;
139
+ }
140
+
37
141
  // ../primitives-web/src/Spinner.tsx
38
142
  var import_styled_components = __toESM(require("styled-components"));
39
143
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -45,7 +149,8 @@ var rotate = import_styled_components.keyframes`
45
149
  transform: rotate(360deg);
46
150
  }
47
151
  `;
48
- var StyledSpinner = import_styled_components.default.div`
152
+ var FilteredDiv = createFilteredElement("div");
153
+ var StyledSpinner = (0, import_styled_components.default)(FilteredDiv)`
49
154
  width: ${(props) => typeof props.size === "number" ? `${props.size}px` : props.size || "24px"};
50
155
  height: ${(props) => typeof props.size === "number" ? `${props.size}px` : props.size || "24px"};
51
156
  border: ${(props) => props.strokeWidth || 2}px solid
package/web/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.tsx","../../../primitives-web/src/Spinner.tsx","../../src/Spinner.tsx"],"sourcesContent":["export * from \"./Spinner\";\n","import React from \"react\";\nimport styled, { keyframes } from \"styled-components\";\nimport type { SpinnerProps } from \"@xsolla/xui-primitives-core\";\n\nconst rotate = keyframes`\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n`;\n\nconst StyledSpinner = styled.div<SpinnerProps>`\n width: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n height: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n border: ${(props) => props.strokeWidth || 2}px solid\n ${(props) => props.color || \"currentColor\"};\n border-bottom-color: transparent;\n border-radius: 50%;\n display: inline-block;\n box-sizing: border-box;\n animation: ${rotate} 1s linear infinite;\n`;\n\nexport const Spinner: React.FC<SpinnerProps> = ({\n role = \"status\",\n \"aria-label\": ariaLabel,\n \"aria-live\": ariaLive = \"polite\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n ...props\n}) => {\n return (\n <StyledSpinner\n role={role}\n aria-label={ariaLabel}\n aria-live={ariaLive}\n aria-describedby={ariaDescribedBy}\n data-testid={testID}\n {...props}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n","import type React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Spinner as SpinnerPrimitive } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\n\nexport interface SpinnerProps extends ThemeOverrideProps {\n /**\n * The size of the spinner.\n * @default 'md'\n */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n /**\n * The color of the spinner.\n * If not provided, it will use the default text color from the theme.\n */\n color?: string;\n /**\n * Accessible label for screen readers.\n * @default 'Loading'\n */\n \"aria-label\"?: string;\n /**\n * ID of the element being loaded (for aria-describedby on the loading container).\n */\n \"aria-describedby\"?: string;\n /**\n * Test ID for testing frameworks.\n */\n testID?: string;\n}\n\n/**\n * Spinner - An accessible loading indicator component\n *\n * Displays a spinning animation to indicate loading state.\n *\n * ## Accessibility Features\n *\n * - **role=\"status\"**: Announces to screen readers that this is a status indicator\n * - **aria-live=\"polite\"**: Screen readers will announce when the spinner appears\n * - **aria-label**: Provides accessible name for the spinner (defaults to \"Loading\")\n *\n * ## Sizes\n *\n * - xl: 96px\n * - l: 48px\n * - m: 24px (default)\n * - s: 16px\n * - xs: 8px\n */\nexport const Spinner: React.FC<SpinnerProps> = ({\n size = \"md\",\n color,\n \"aria-label\": ariaLabel = \"Loading\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const sizeConfig = theme.sizing.spinner(size);\n const defaultColor = theme.colors.content.primary;\n\n return (\n <SpinnerPrimitive\n size={sizeConfig.size}\n strokeWidth={sizeConfig.strokeWidth}\n color={color || defaultColor}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n testID={testID}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,iBAAAA;AAAA;AAAA;;;ACCA,+BAAkC;AAmC9B;AAhCJ,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASf,IAAM,gBAAgB,yBAAAC,QAAO;AAAA,WAClB,CAAC,UACR,OAAO,MAAM,SAAS,WAAW,GAAG,MAAM,IAAI,OAAO,MAAM,QAAQ,MAAM;AAAA,YACjE,CAAC,UACT,OAAO,MAAM,SAAS,WAAW,GAAG,MAAM,IAAI,OAAO,MAAM,QAAQ,MAAM;AAAA,YACjE,CAAC,UAAU,MAAM,eAAe,CAAC;AAAA,MACvC,CAAC,UAAU,MAAM,SAAS,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,eAK/B,MAAM;AAAA;AAGd,IAAM,UAAkC,CAAC;AAAA,EAC9C,OAAO;AAAA,EACP,cAAc;AAAA,EACd,aAAa,WAAW;AAAA,EACxB,oBAAoB;AAAA,EACpB;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAY;AAAA,MACZ,aAAW;AAAA,MACX,oBAAkB;AAAA,MAClB,eAAa;AAAA,MACZ,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,QAAQ,cAAc;;;AC5CtB,sBAA0D;AA8DtD,IAAAC,sBAAA;AAfG,IAAMC,WAAkC,CAAC;AAAA,EAC9C,OAAO;AAAA,EACP;AAAA,EACA,cAAc,YAAY;AAAA,EAC1B,oBAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,MAAM,QAAI,kCAAiB,EAAE,WAAW,oBAAoB,CAAC;AAErE,QAAM,aAAa,MAAM,OAAO,QAAQ,IAAI;AAC5C,QAAM,eAAe,MAAM,OAAO,QAAQ;AAE1C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,WAAW;AAAA,MACjB,aAAa,WAAW;AAAA,MACxB,OAAO,SAAS;AAAA,MAChB,MAAK;AAAA,MACL,aAAU;AAAA,MACV,cAAY;AAAA,MACZ,oBAAkB;AAAA,MAClB;AAAA;AAAA,EACF;AAEJ;AAEAA,SAAQ,cAAc;","names":["Spinner","styled","import_jsx_runtime","Spinner"]}
1
+ {"version":3,"sources":["../../src/index.tsx","../../../primitives-web/src/filterDOMProps.ts","../../../primitives-web/src/Spinner.tsx","../../src/Spinner.tsx"],"sourcesContent":["export * from \"./Spinner\";\n","import React from \"react\";\n\n// Props from BoxProps, TextProps, SpinnerProps, IconProps, DividerProps\n// that are NOT valid HTML attributes and must not reach the DOM.\nexport const NON_HTML_PROPS = new Set([\n // BoxProps — layout & styling\n \"backgroundColor\",\n \"borderColor\",\n \"borderWidth\",\n \"borderBottomWidth\",\n \"borderBottomColor\",\n \"borderTopWidth\",\n \"borderTopColor\",\n \"borderLeftWidth\",\n \"borderLeftColor\",\n \"borderRightWidth\",\n \"borderRightColor\",\n \"borderRadius\",\n \"borderStyle\",\n \"flexDirection\",\n \"flexWrap\",\n \"alignItems\",\n \"justifyContent\",\n \"alignSelf\",\n \"flex\",\n \"flexShrink\",\n \"gap\",\n \"position\",\n \"top\",\n \"bottom\",\n \"left\",\n \"right\",\n \"outline\",\n \"overflow\",\n \"overflowX\",\n \"overflowY\",\n \"zIndex\",\n \"cursor\",\n \"padding\",\n \"paddingHorizontal\",\n \"paddingVertical\",\n \"paddingTop\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"paddingRight\",\n \"margin\",\n \"marginTop\",\n \"marginBottom\",\n \"marginLeft\",\n \"marginRight\",\n \"minWidth\",\n \"minHeight\",\n \"maxWidth\",\n \"maxHeight\",\n \"hoverStyle\",\n \"pressStyle\",\n \"focusStyle\",\n \"outlineColor\",\n \"outlineWidth\",\n \"outlineOffset\",\n \"outlineStyle\",\n // BoxProps — RN-only\n \"onPress\",\n \"onLayout\",\n \"onMoveShouldSetResponder\",\n \"onResponderGrant\",\n \"onResponderMove\",\n \"onResponderRelease\",\n \"onResponderTerminate\",\n \"testID\",\n // Box — custom element type\n \"elementType\",\n // TextProps\n \"fontSize\",\n \"fontWeight\",\n \"fontFamily\",\n \"lineHeight\",\n \"whiteSpace\",\n \"textAlign\",\n \"textDecoration\",\n \"numberOfLines\",\n \"letterSpacing\",\n \"textTransform\",\n // SpinnerProps\n \"strokeWidth\",\n // DividerProps\n \"vertical\",\n \"dashStroke\",\n]);\n\n/**\n * Creates a React component that renders the given HTML tag\n * but filters out non-HTML props before they reach the DOM.\n *\n * Usage: `const FilteredDiv = createFilteredElement(\"div\");`\n * Then: `const StyledBox = styled(FilteredDiv)<BoxProps>\\`...\\`;`\n *\n * styled-components can still read ALL props for CSS interpolation,\n * but only valid HTML attributes are forwarded to the DOM element.\n */\nexport function createFilteredElement(defaultTag: string) {\n const Component = React.forwardRef<HTMLElement, any>(\n ({ children, elementType, ...props }, ref) => {\n const Tag = elementType || defaultTag;\n const htmlProps: Record<string, unknown> = {};\n for (const key of Object.keys(props)) {\n if (!NON_HTML_PROPS.has(key)) {\n htmlProps[key] = props[key];\n }\n }\n return React.createElement(Tag, { ref, ...htmlProps }, children);\n }\n );\n Component.displayName = `Filtered(${defaultTag})`;\n return Component;\n}\n","import React from \"react\";\nimport styled, { keyframes } from \"styled-components\";\nimport type { SpinnerProps } from \"@xsolla/xui-primitives-core\";\nimport { createFilteredElement } from \"./filterDOMProps\";\n\nconst rotate = keyframes`\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n`;\n\nconst FilteredDiv = createFilteredElement(\"div\");\n\nconst StyledSpinner = styled(FilteredDiv)<SpinnerProps>`\n width: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n height: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n border: ${(props) => props.strokeWidth || 2}px solid\n ${(props) => props.color || \"currentColor\"};\n border-bottom-color: transparent;\n border-radius: 50%;\n display: inline-block;\n box-sizing: border-box;\n animation: ${rotate} 1s linear infinite;\n`;\n\nexport const Spinner: React.FC<SpinnerProps> = ({\n role = \"status\",\n \"aria-label\": ariaLabel,\n \"aria-live\": ariaLive = \"polite\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n ...props\n}) => {\n return (\n <StyledSpinner\n role={role}\n aria-label={ariaLabel}\n aria-live={ariaLive}\n aria-describedby={ariaDescribedBy}\n data-testid={testID}\n {...props}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n","import type React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Spinner as SpinnerPrimitive } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\n\nexport interface SpinnerProps extends ThemeOverrideProps {\n /**\n * The size of the spinner.\n * @default 'md'\n */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n /**\n * The color of the spinner.\n * If not provided, it will use the default text color from the theme.\n */\n color?: string;\n /**\n * Accessible label for screen readers.\n * @default 'Loading'\n */\n \"aria-label\"?: string;\n /**\n * ID of the element being loaded (for aria-describedby on the loading container).\n */\n \"aria-describedby\"?: string;\n /**\n * Test ID for testing frameworks.\n */\n testID?: string;\n}\n\n/**\n * Spinner - An accessible loading indicator component\n *\n * Displays a spinning animation to indicate loading state.\n *\n * ## Accessibility Features\n *\n * - **role=\"status\"**: Announces to screen readers that this is a status indicator\n * - **aria-live=\"polite\"**: Screen readers will announce when the spinner appears\n * - **aria-label**: Provides accessible name for the spinner (defaults to \"Loading\")\n *\n * ## Sizes\n *\n * - xl: 96px\n * - l: 48px\n * - m: 24px (default)\n * - s: 16px\n * - xs: 8px\n */\nexport const Spinner: React.FC<SpinnerProps> = ({\n size = \"md\",\n color,\n \"aria-label\": ariaLabel = \"Loading\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const sizeConfig = theme.sizing.spinner(size);\n const defaultColor = theme.colors.content.primary;\n\n return (\n <SpinnerPrimitive\n size={sizeConfig.size}\n strokeWidth={sizeConfig.strokeWidth}\n color={color || defaultColor}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n testID={testID}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n"],"mappings":"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","names":["Spinner","React","styled","import_jsx_runtime","Spinner"]}
package/web/index.mjs CHANGED
@@ -1,3 +1,107 @@
1
+ // ../primitives-web/src/filterDOMProps.ts
2
+ import React from "react";
3
+ var NON_HTML_PROPS = /* @__PURE__ */ new Set([
4
+ // BoxProps — layout & styling
5
+ "backgroundColor",
6
+ "borderColor",
7
+ "borderWidth",
8
+ "borderBottomWidth",
9
+ "borderBottomColor",
10
+ "borderTopWidth",
11
+ "borderTopColor",
12
+ "borderLeftWidth",
13
+ "borderLeftColor",
14
+ "borderRightWidth",
15
+ "borderRightColor",
16
+ "borderRadius",
17
+ "borderStyle",
18
+ "flexDirection",
19
+ "flexWrap",
20
+ "alignItems",
21
+ "justifyContent",
22
+ "alignSelf",
23
+ "flex",
24
+ "flexShrink",
25
+ "gap",
26
+ "position",
27
+ "top",
28
+ "bottom",
29
+ "left",
30
+ "right",
31
+ "outline",
32
+ "overflow",
33
+ "overflowX",
34
+ "overflowY",
35
+ "zIndex",
36
+ "cursor",
37
+ "padding",
38
+ "paddingHorizontal",
39
+ "paddingVertical",
40
+ "paddingTop",
41
+ "paddingBottom",
42
+ "paddingLeft",
43
+ "paddingRight",
44
+ "margin",
45
+ "marginTop",
46
+ "marginBottom",
47
+ "marginLeft",
48
+ "marginRight",
49
+ "minWidth",
50
+ "minHeight",
51
+ "maxWidth",
52
+ "maxHeight",
53
+ "hoverStyle",
54
+ "pressStyle",
55
+ "focusStyle",
56
+ "outlineColor",
57
+ "outlineWidth",
58
+ "outlineOffset",
59
+ "outlineStyle",
60
+ // BoxProps — RN-only
61
+ "onPress",
62
+ "onLayout",
63
+ "onMoveShouldSetResponder",
64
+ "onResponderGrant",
65
+ "onResponderMove",
66
+ "onResponderRelease",
67
+ "onResponderTerminate",
68
+ "testID",
69
+ // Box — custom element type
70
+ "elementType",
71
+ // TextProps
72
+ "fontSize",
73
+ "fontWeight",
74
+ "fontFamily",
75
+ "lineHeight",
76
+ "whiteSpace",
77
+ "textAlign",
78
+ "textDecoration",
79
+ "numberOfLines",
80
+ "letterSpacing",
81
+ "textTransform",
82
+ // SpinnerProps
83
+ "strokeWidth",
84
+ // DividerProps
85
+ "vertical",
86
+ "dashStroke"
87
+ ]);
88
+ function createFilteredElement(defaultTag) {
89
+ const Component = React.forwardRef(
90
+ ({ children, elementType, ...props }, ref) => {
91
+ const Tag = elementType || defaultTag;
92
+ const htmlProps = {};
93
+ for (const key of Object.keys(props)) {
94
+ if (!NON_HTML_PROPS.has(key)) {
95
+ htmlProps[key] = props[key];
96
+ }
97
+ }
98
+ return React.createElement(Tag, { ref, ...htmlProps }, children);
99
+ }
100
+ );
101
+ Component.displayName = `Filtered(${defaultTag})`;
102
+ return Component;
103
+ }
104
+
1
105
  // ../primitives-web/src/Spinner.tsx
2
106
  import styled, { keyframes } from "styled-components";
3
107
  import { jsx } from "react/jsx-runtime";
@@ -9,7 +113,8 @@ var rotate = keyframes`
9
113
  transform: rotate(360deg);
10
114
  }
11
115
  `;
12
- var StyledSpinner = styled.div`
116
+ var FilteredDiv = createFilteredElement("div");
117
+ var StyledSpinner = styled(FilteredDiv)`
13
118
  width: ${(props) => typeof props.size === "number" ? `${props.size}px` : props.size || "24px"};
14
119
  height: ${(props) => typeof props.size === "number" ? `${props.size}px` : props.size || "24px"};
15
120
  border: ${(props) => props.strokeWidth || 2}px solid
package/web/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../primitives-web/src/Spinner.tsx","../../src/Spinner.tsx"],"sourcesContent":["import React from \"react\";\nimport styled, { keyframes } from \"styled-components\";\nimport type { SpinnerProps } from \"@xsolla/xui-primitives-core\";\n\nconst rotate = keyframes`\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n`;\n\nconst StyledSpinner = styled.div<SpinnerProps>`\n width: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n height: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n border: ${(props) => props.strokeWidth || 2}px solid\n ${(props) => props.color || \"currentColor\"};\n border-bottom-color: transparent;\n border-radius: 50%;\n display: inline-block;\n box-sizing: border-box;\n animation: ${rotate} 1s linear infinite;\n`;\n\nexport const Spinner: React.FC<SpinnerProps> = ({\n role = \"status\",\n \"aria-label\": ariaLabel,\n \"aria-live\": ariaLive = \"polite\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n ...props\n}) => {\n return (\n <StyledSpinner\n role={role}\n aria-label={ariaLabel}\n aria-live={ariaLive}\n aria-describedby={ariaDescribedBy}\n data-testid={testID}\n {...props}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n","import type React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Spinner as SpinnerPrimitive } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\n\nexport interface SpinnerProps extends ThemeOverrideProps {\n /**\n * The size of the spinner.\n * @default 'md'\n */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n /**\n * The color of the spinner.\n * If not provided, it will use the default text color from the theme.\n */\n color?: string;\n /**\n * Accessible label for screen readers.\n * @default 'Loading'\n */\n \"aria-label\"?: string;\n /**\n * ID of the element being loaded (for aria-describedby on the loading container).\n */\n \"aria-describedby\"?: string;\n /**\n * Test ID for testing frameworks.\n */\n testID?: string;\n}\n\n/**\n * Spinner - An accessible loading indicator component\n *\n * Displays a spinning animation to indicate loading state.\n *\n * ## Accessibility Features\n *\n * - **role=\"status\"**: Announces to screen readers that this is a status indicator\n * - **aria-live=\"polite\"**: Screen readers will announce when the spinner appears\n * - **aria-label**: Provides accessible name for the spinner (defaults to \"Loading\")\n *\n * ## Sizes\n *\n * - xl: 96px\n * - l: 48px\n * - m: 24px (default)\n * - s: 16px\n * - xs: 8px\n */\nexport const Spinner: React.FC<SpinnerProps> = ({\n size = \"md\",\n color,\n \"aria-label\": ariaLabel = \"Loading\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const sizeConfig = theme.sizing.spinner(size);\n const defaultColor = theme.colors.content.primary;\n\n return (\n <SpinnerPrimitive\n size={sizeConfig.size}\n strokeWidth={sizeConfig.strokeWidth}\n color={color || defaultColor}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n testID={testID}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n"],"mappings":";AACA,OAAO,UAAU,iBAAiB;AAmC9B;AAhCJ,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASf,IAAM,gBAAgB,OAAO;AAAA,WAClB,CAAC,UACR,OAAO,MAAM,SAAS,WAAW,GAAG,MAAM,IAAI,OAAO,MAAM,QAAQ,MAAM;AAAA,YACjE,CAAC,UACT,OAAO,MAAM,SAAS,WAAW,GAAG,MAAM,IAAI,OAAO,MAAM,QAAQ,MAAM;AAAA,YACjE,CAAC,UAAU,MAAM,eAAe,CAAC;AAAA,MACvC,CAAC,UAAU,MAAM,SAAS,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,eAK/B,MAAM;AAAA;AAGd,IAAM,UAAkC,CAAC;AAAA,EAC9C,OAAO;AAAA,EACP,cAAc;AAAA,EACd,aAAa,WAAW;AAAA,EACxB,oBAAoB;AAAA,EACpB;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAY;AAAA,MACZ,aAAW;AAAA,MACX,oBAAkB;AAAA,MAClB,eAAa;AAAA,MACZ,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,QAAQ,cAAc;;;AC5CtB,SAAS,wBAAiD;AA8DtD,gBAAAA,YAAA;AAfG,IAAMC,WAAkC,CAAC;AAAA,EAC9C,OAAO;AAAA,EACP;AAAA,EACA,cAAc,YAAY;AAAA,EAC1B,oBAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,MAAM,IAAI,iBAAiB,EAAE,WAAW,oBAAoB,CAAC;AAErE,QAAM,aAAa,MAAM,OAAO,QAAQ,IAAI;AAC5C,QAAM,eAAe,MAAM,OAAO,QAAQ;AAE1C,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,WAAW;AAAA,MACjB,aAAa,WAAW;AAAA,MACxB,OAAO,SAAS;AAAA,MAChB,MAAK;AAAA,MACL,aAAU;AAAA,MACV,cAAY;AAAA,MACZ,oBAAkB;AAAA,MAClB;AAAA;AAAA,EACF;AAEJ;AAEAC,SAAQ,cAAc;","names":["jsx","Spinner"]}
1
+ {"version":3,"sources":["../../../primitives-web/src/filterDOMProps.ts","../../../primitives-web/src/Spinner.tsx","../../src/Spinner.tsx"],"sourcesContent":["import React from \"react\";\n\n// Props from BoxProps, TextProps, SpinnerProps, IconProps, DividerProps\n// that are NOT valid HTML attributes and must not reach the DOM.\nexport const NON_HTML_PROPS = new Set([\n // BoxProps — layout & styling\n \"backgroundColor\",\n \"borderColor\",\n \"borderWidth\",\n \"borderBottomWidth\",\n \"borderBottomColor\",\n \"borderTopWidth\",\n \"borderTopColor\",\n \"borderLeftWidth\",\n \"borderLeftColor\",\n \"borderRightWidth\",\n \"borderRightColor\",\n \"borderRadius\",\n \"borderStyle\",\n \"flexDirection\",\n \"flexWrap\",\n \"alignItems\",\n \"justifyContent\",\n \"alignSelf\",\n \"flex\",\n \"flexShrink\",\n \"gap\",\n \"position\",\n \"top\",\n \"bottom\",\n \"left\",\n \"right\",\n \"outline\",\n \"overflow\",\n \"overflowX\",\n \"overflowY\",\n \"zIndex\",\n \"cursor\",\n \"padding\",\n \"paddingHorizontal\",\n \"paddingVertical\",\n \"paddingTop\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"paddingRight\",\n \"margin\",\n \"marginTop\",\n \"marginBottom\",\n \"marginLeft\",\n \"marginRight\",\n \"minWidth\",\n \"minHeight\",\n \"maxWidth\",\n \"maxHeight\",\n \"hoverStyle\",\n \"pressStyle\",\n \"focusStyle\",\n \"outlineColor\",\n \"outlineWidth\",\n \"outlineOffset\",\n \"outlineStyle\",\n // BoxProps — RN-only\n \"onPress\",\n \"onLayout\",\n \"onMoveShouldSetResponder\",\n \"onResponderGrant\",\n \"onResponderMove\",\n \"onResponderRelease\",\n \"onResponderTerminate\",\n \"testID\",\n // Box — custom element type\n \"elementType\",\n // TextProps\n \"fontSize\",\n \"fontWeight\",\n \"fontFamily\",\n \"lineHeight\",\n \"whiteSpace\",\n \"textAlign\",\n \"textDecoration\",\n \"numberOfLines\",\n \"letterSpacing\",\n \"textTransform\",\n // SpinnerProps\n \"strokeWidth\",\n // DividerProps\n \"vertical\",\n \"dashStroke\",\n]);\n\n/**\n * Creates a React component that renders the given HTML tag\n * but filters out non-HTML props before they reach the DOM.\n *\n * Usage: `const FilteredDiv = createFilteredElement(\"div\");`\n * Then: `const StyledBox = styled(FilteredDiv)<BoxProps>\\`...\\`;`\n *\n * styled-components can still read ALL props for CSS interpolation,\n * but only valid HTML attributes are forwarded to the DOM element.\n */\nexport function createFilteredElement(defaultTag: string) {\n const Component = React.forwardRef<HTMLElement, any>(\n ({ children, elementType, ...props }, ref) => {\n const Tag = elementType || defaultTag;\n const htmlProps: Record<string, unknown> = {};\n for (const key of Object.keys(props)) {\n if (!NON_HTML_PROPS.has(key)) {\n htmlProps[key] = props[key];\n }\n }\n return React.createElement(Tag, { ref, ...htmlProps }, children);\n }\n );\n Component.displayName = `Filtered(${defaultTag})`;\n return Component;\n}\n","import React from \"react\";\nimport styled, { keyframes } from \"styled-components\";\nimport type { SpinnerProps } from \"@xsolla/xui-primitives-core\";\nimport { createFilteredElement } from \"./filterDOMProps\";\n\nconst rotate = keyframes`\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n`;\n\nconst FilteredDiv = createFilteredElement(\"div\");\n\nconst StyledSpinner = styled(FilteredDiv)<SpinnerProps>`\n width: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n height: ${(props) =>\n typeof props.size === \"number\" ? `${props.size}px` : props.size || \"24px\"};\n border: ${(props) => props.strokeWidth || 2}px solid\n ${(props) => props.color || \"currentColor\"};\n border-bottom-color: transparent;\n border-radius: 50%;\n display: inline-block;\n box-sizing: border-box;\n animation: ${rotate} 1s linear infinite;\n`;\n\nexport const Spinner: React.FC<SpinnerProps> = ({\n role = \"status\",\n \"aria-label\": ariaLabel,\n \"aria-live\": ariaLive = \"polite\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n ...props\n}) => {\n return (\n <StyledSpinner\n role={role}\n aria-label={ariaLabel}\n aria-live={ariaLive}\n aria-describedby={ariaDescribedBy}\n data-testid={testID}\n {...props}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n","import type React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Spinner as SpinnerPrimitive } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\n\nexport interface SpinnerProps extends ThemeOverrideProps {\n /**\n * The size of the spinner.\n * @default 'md'\n */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n /**\n * The color of the spinner.\n * If not provided, it will use the default text color from the theme.\n */\n color?: string;\n /**\n * Accessible label for screen readers.\n * @default 'Loading'\n */\n \"aria-label\"?: string;\n /**\n * ID of the element being loaded (for aria-describedby on the loading container).\n */\n \"aria-describedby\"?: string;\n /**\n * Test ID for testing frameworks.\n */\n testID?: string;\n}\n\n/**\n * Spinner - An accessible loading indicator component\n *\n * Displays a spinning animation to indicate loading state.\n *\n * ## Accessibility Features\n *\n * - **role=\"status\"**: Announces to screen readers that this is a status indicator\n * - **aria-live=\"polite\"**: Screen readers will announce when the spinner appears\n * - **aria-label**: Provides accessible name for the spinner (defaults to \"Loading\")\n *\n * ## Sizes\n *\n * - xl: 96px\n * - l: 48px\n * - m: 24px (default)\n * - s: 16px\n * - xs: 8px\n */\nexport const Spinner: React.FC<SpinnerProps> = ({\n size = \"md\",\n color,\n \"aria-label\": ariaLabel = \"Loading\",\n \"aria-describedby\": ariaDescribedBy,\n testID,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const sizeConfig = theme.sizing.spinner(size);\n const defaultColor = theme.colors.content.primary;\n\n return (\n <SpinnerPrimitive\n size={sizeConfig.size}\n strokeWidth={sizeConfig.strokeWidth}\n color={color || defaultColor}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n testID={testID}\n />\n );\n};\n\nSpinner.displayName = \"Spinner\";\n"],"mappings":"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","names":["jsx","Spinner"]}