@xsolla/xui-gradient-picker 0.204.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/web/index.js ADDED
@@ -0,0 +1,1096 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ DEFAULT_GRADIENT: () => DEFAULT_GRADIENT,
34
+ GradientPicker: () => GradientPicker,
35
+ GradientStopMarker: () => GradientStopMarker,
36
+ addStopAt: () => addStopAt,
37
+ interpolateColorAt: () => interpolateColorAt,
38
+ removeStop: () => removeStop,
39
+ sortStops: () => sortStops,
40
+ supportsAngle: () => supportsAngle,
41
+ toCssGradient: () => toCssGradient,
42
+ toPreviewCssGradient: () => toPreviewCssGradient,
43
+ updateStop: () => updateStop
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/GradientPicker.tsx
48
+ var import_react3 = require("react");
49
+
50
+ // ../../foundation/primitives-web/src/Box.tsx
51
+ var import_react2 = __toESM(require("react"));
52
+ var import_styled_components = __toESM(require("styled-components"));
53
+
54
+ // ../../foundation/primitives-web/src/filterDOMProps.ts
55
+ var import_react = __toESM(require("react"));
56
+
57
+ // ../../../node_modules/@emotion/memoize/dist/memoize.esm.js
58
+ function memoize(fn) {
59
+ var cache = {};
60
+ return function(arg) {
61
+ if (cache[arg] === void 0) cache[arg] = fn(arg);
62
+ return cache[arg];
63
+ };
64
+ }
65
+ var memoize_esm_default = memoize;
66
+
67
+ // ../../../node_modules/@emotion/is-prop-valid/dist/is-prop-valid.esm.js
68
+ var reactPropsRegex = /^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|suppressHydrationWarning|valueLink|accept|acceptCharset|accessKey|action|allow|allowUserMedia|allowPaymentRequest|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|decoding|default|defer|dir|disabled|disablePictureInPicture|download|draggable|encType|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loading|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|inert|itemProp|itemScope|itemType|itemID|itemRef|on|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class|autofocus)|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/;
69
+ var index = memoize_esm_default(
70
+ function(prop) {
71
+ return reactPropsRegex.test(prop) || prop.charCodeAt(0) === 111 && prop.charCodeAt(1) === 110 && prop.charCodeAt(2) < 91;
72
+ }
73
+ /* Z+1 */
74
+ );
75
+ var is_prop_valid_esm_default = index;
76
+
77
+ // ../../foundation/primitives-web/src/filterDOMProps.ts
78
+ var ADDITIONAL_BLOCKED_PROPS = /* @__PURE__ */ new Set([
79
+ // RN-only event handlers (pass isPropValid's on* pattern)
80
+ "onPress",
81
+ "onChangeText",
82
+ "onLayout",
83
+ "onMoveShouldSetResponder",
84
+ "onResponderGrant",
85
+ "onResponderMove",
86
+ "onResponderRelease",
87
+ "onResponderTerminate",
88
+ // SVG attributes that pass isPropValid
89
+ "strokeWidth",
90
+ // CSS properties that pass isPropValid but are used as component props
91
+ "overflow",
92
+ "opacity",
93
+ "cursor",
94
+ "fontSize",
95
+ "fontWeight",
96
+ "fontFamily",
97
+ "textDecoration",
98
+ // Cross-platform layout prop that Text consumes as CSS, never as an
99
+ // attribute. Pinned explicitly because it is now spread into the styled
100
+ // component rather than destructured away before it can reach the DOM.
101
+ "numberOfLines"
102
+ ]);
103
+ function shouldForwardProp(key) {
104
+ if (ADDITIONAL_BLOCKED_PROPS.has(key)) return false;
105
+ return is_prop_valid_esm_default(key);
106
+ }
107
+ function createFilteredElement(defaultTag) {
108
+ const Component = import_react.default.forwardRef(
109
+ ({ children, elementType, ...props }, ref) => {
110
+ const Tag = elementType || defaultTag;
111
+ const htmlProps = {};
112
+ for (const key of Object.keys(props)) {
113
+ if (shouldForwardProp(key)) {
114
+ htmlProps[key] = props[key];
115
+ }
116
+ }
117
+ return import_react.default.createElement(
118
+ Tag,
119
+ { ref, ...htmlProps },
120
+ children
121
+ );
122
+ }
123
+ );
124
+ Component.displayName = `Filtered(${defaultTag})`;
125
+ return Component;
126
+ }
127
+
128
+ // ../../foundation/primitives-web/src/Box.tsx
129
+ var import_jsx_runtime = require("react/jsx-runtime");
130
+ var FilteredDiv = createFilteredElement("div");
131
+ var StyledBox = (0, import_styled_components.default)(FilteredDiv)`
132
+ display: flex;
133
+ box-sizing: border-box;
134
+ background-color: ${(props) => props.backgroundColor || "transparent"};
135
+ border-color: ${(props) => props.borderColor || "transparent"};
136
+ border-width: ${(props) => typeof props.borderWidth === "number" ? `${props.borderWidth}px` : props.borderWidth || 0};
137
+
138
+ ${(props) => props.borderBottomWidth !== void 0 && `
139
+ border-bottom-width: ${typeof props.borderBottomWidth === "number" ? `${props.borderBottomWidth}px` : props.borderBottomWidth};
140
+ border-bottom-color: ${props.borderBottomColor || props.borderColor || "transparent"};
141
+ border-bottom-style: solid;
142
+ `}
143
+ ${(props) => props.borderTopWidth !== void 0 && `
144
+ border-top-width: ${typeof props.borderTopWidth === "number" ? `${props.borderTopWidth}px` : props.borderTopWidth};
145
+ border-top-color: ${props.borderTopColor || props.borderColor || "transparent"};
146
+ border-top-style: solid;
147
+ `}
148
+ ${(props) => props.borderLeftWidth !== void 0 && `
149
+ border-left-width: ${typeof props.borderLeftWidth === "number" ? `${props.borderLeftWidth}px` : props.borderLeftWidth};
150
+ border-left-color: ${props.borderLeftColor || props.borderColor || "transparent"};
151
+ border-left-style: solid;
152
+ `}
153
+ ${(props) => props.borderRightWidth !== void 0 && `
154
+ border-right-width: ${typeof props.borderRightWidth === "number" ? `${props.borderRightWidth}px` : props.borderRightWidth};
155
+ border-right-color: ${props.borderRightColor || props.borderColor || "transparent"};
156
+ border-right-style: solid;
157
+ `}
158
+
159
+ border-style: ${(props) => props.borderStyle || (props.borderWidth || props.borderBottomWidth || props.borderTopWidth || props.borderLeftWidth || props.borderRightWidth ? "solid" : "none")};
160
+ border-radius: ${(props) => typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius || 0};
161
+ height: ${(props) => typeof props.height === "number" ? `${props.height}px` : props.height || "auto"};
162
+ width: ${(props) => typeof props.width === "number" ? `${props.width}px` : props.width || "auto"};
163
+ min-width: ${(props) => typeof props.minWidth === "number" ? `${props.minWidth}px` : props.minWidth || "auto"};
164
+ min-height: ${(props) => typeof props.minHeight === "number" ? `${props.minHeight}px` : props.minHeight || "auto"};
165
+ max-width: ${(props) => typeof props.maxWidth === "number" ? `${props.maxWidth}px` : props.maxWidth || "none"};
166
+ max-height: ${(props) => typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight || "none"};
167
+
168
+ padding: ${(props) => typeof props.padding === "number" ? `${props.padding}px` : props.padding || 0};
169
+ ${(props) => props.paddingHorizontal && `
170
+ padding-left: ${typeof props.paddingHorizontal === "number" ? `${props.paddingHorizontal}px` : props.paddingHorizontal};
171
+ padding-right: ${typeof props.paddingHorizontal === "number" ? `${props.paddingHorizontal}px` : props.paddingHorizontal};
172
+ `}
173
+ ${(props) => props.paddingVertical && `
174
+ padding-top: ${typeof props.paddingVertical === "number" ? `${props.paddingVertical}px` : props.paddingVertical};
175
+ padding-bottom: ${typeof props.paddingVertical === "number" ? `${props.paddingVertical}px` : props.paddingVertical};
176
+ `}
177
+ ${(props) => props.paddingTop !== void 0 && `padding-top: ${typeof props.paddingTop === "number" ? `${props.paddingTop}px` : props.paddingTop};`}
178
+ ${(props) => props.paddingBottom !== void 0 && `padding-bottom: ${typeof props.paddingBottom === "number" ? `${props.paddingBottom}px` : props.paddingBottom};`}
179
+ ${(props) => props.paddingLeft !== void 0 && `padding-left: ${typeof props.paddingLeft === "number" ? `${props.paddingLeft}px` : props.paddingLeft};`}
180
+ ${(props) => props.paddingRight !== void 0 && `padding-right: ${typeof props.paddingRight === "number" ? `${props.paddingRight}px` : props.paddingRight};`}
181
+
182
+ margin: ${(props) => typeof props.margin === "number" ? `${props.margin}px` : props.margin || 0};
183
+ ${(props) => props.marginTop !== void 0 && `margin-top: ${typeof props.marginTop === "number" ? `${props.marginTop}px` : props.marginTop};`}
184
+ ${(props) => props.marginBottom !== void 0 && `margin-bottom: ${typeof props.marginBottom === "number" ? `${props.marginBottom}px` : props.marginBottom};`}
185
+ ${(props) => props.marginLeft !== void 0 && `margin-left: ${typeof props.marginLeft === "number" ? `${props.marginLeft}px` : props.marginLeft};`}
186
+ ${(props) => props.marginRight !== void 0 && `margin-right: ${typeof props.marginRight === "number" ? `${props.marginRight}px` : props.marginRight};`}
187
+
188
+ flex-direction: ${(props) => props.flexDirection || "column"};
189
+ flex-wrap: ${(props) => props.flexWrap || "nowrap"};
190
+ align-items: ${(props) => props.alignItems || "stretch"};
191
+ justify-content: ${(props) => props.justifyContent || "flex-start"};
192
+ cursor: ${(props) => props.cursor ? props.cursor : props.onClick || props.onPress ? "pointer" : "inherit"};
193
+ position: ${(props) => props.position || "static"};
194
+ top: ${(props) => typeof props.top === "number" ? `${props.top}px` : props.top};
195
+ bottom: ${(props) => typeof props.bottom === "number" ? `${props.bottom}px` : props.bottom};
196
+ left: ${(props) => typeof props.left === "number" ? `${props.left}px` : props.left};
197
+ right: ${(props) => typeof props.right === "number" ? `${props.right}px` : props.right};
198
+ flex: ${(props) => props.flex};
199
+ flex-shrink: ${(props) => props.flexShrink ?? 1};
200
+ gap: ${(props) => typeof props.gap === "number" ? `${props.gap}px` : props.gap || 0};
201
+ align-self: ${(props) => props.alignSelf || "auto"};
202
+ /* Only emit overflow-x/y when explicitly set. Defaulting them to
203
+ visible after overflow would override the shorthand and break
204
+ clipping (e.g. OtherCard bottom-right promo image). */
205
+ overflow: ${(props) => props.overflow || "visible"};
206
+ ${(props) => props.overflowX != null ? `overflow-x: ${props.overflowX};` : ""}
207
+ ${(props) => props.overflowY != null ? `overflow-y: ${props.overflowY};` : ""}
208
+ z-index: ${(props) => props.zIndex};
209
+ opacity: ${(props) => props.opacity != null ? props.opacity : props.disabled ? 0.5 : 1};
210
+ pointer-events: ${(props) => props.disabled ? "none" : "auto"};
211
+
212
+ &:hover {
213
+ ${(props) => props.hoverStyle?.backgroundColor && `background-color: ${props.hoverStyle.backgroundColor};`}
214
+ ${(props) => props.hoverStyle?.borderColor && `border-color: ${props.hoverStyle.borderColor};`}
215
+ }
216
+
217
+ &:active {
218
+ ${(props) => props.pressStyle?.backgroundColor && `background-color: ${props.pressStyle.backgroundColor};`}
219
+ }
220
+ `;
221
+ var Box = import_react2.default.forwardRef(
222
+ ({
223
+ children,
224
+ onPress,
225
+ onKeyDown,
226
+ onKeyUp,
227
+ role,
228
+ "aria-label": ariaLabel,
229
+ "aria-labelledby": ariaLabelledBy,
230
+ "aria-current": ariaCurrent,
231
+ "aria-disabled": ariaDisabled,
232
+ "aria-live": ariaLive,
233
+ "aria-busy": ariaBusy,
234
+ "aria-describedby": ariaDescribedBy,
235
+ "aria-expanded": ariaExpanded,
236
+ "aria-haspopup": ariaHasPopup,
237
+ "aria-pressed": ariaPressed,
238
+ "aria-controls": ariaControls,
239
+ tabIndex,
240
+ as,
241
+ src,
242
+ alt,
243
+ onError,
244
+ onLoad,
245
+ type,
246
+ disabled,
247
+ id,
248
+ testID,
249
+ "data-testid": dataTestId,
250
+ ...props
251
+ }, ref) => {
252
+ if (as === "img" && src) {
253
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
254
+ "img",
255
+ {
256
+ src,
257
+ alt: alt || "",
258
+ onError,
259
+ onLoad,
260
+ "data-testid": dataTestId || testID,
261
+ style: {
262
+ display: "block",
263
+ objectFit: "cover",
264
+ width: typeof props.width === "number" ? `${props.width}px` : props.width,
265
+ height: typeof props.height === "number" ? `${props.height}px` : props.height,
266
+ borderRadius: typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius,
267
+ position: props.position,
268
+ top: typeof props.top === "number" ? `${props.top}px` : props.top,
269
+ left: typeof props.left === "number" ? `${props.left}px` : props.left,
270
+ right: typeof props.right === "number" ? `${props.right}px` : props.right,
271
+ bottom: typeof props.bottom === "number" ? `${props.bottom}px` : props.bottom,
272
+ ...props.style
273
+ }
274
+ }
275
+ );
276
+ }
277
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
278
+ StyledBox,
279
+ {
280
+ ref,
281
+ elementType: as,
282
+ id,
283
+ type: as === "button" ? type || "button" : void 0,
284
+ disabled: as === "button" ? disabled : void 0,
285
+ onClick: onPress,
286
+ onKeyDown,
287
+ onKeyUp,
288
+ role,
289
+ "aria-label": ariaLabel,
290
+ "aria-labelledby": ariaLabelledBy,
291
+ "aria-current": ariaCurrent,
292
+ "aria-disabled": ariaDisabled,
293
+ "aria-busy": ariaBusy,
294
+ "aria-describedby": ariaDescribedBy,
295
+ "aria-expanded": ariaExpanded,
296
+ "aria-haspopup": ariaHasPopup,
297
+ "aria-pressed": ariaPressed,
298
+ "aria-controls": ariaControls,
299
+ "aria-live": ariaLive,
300
+ tabIndex: tabIndex !== void 0 ? tabIndex : void 0,
301
+ "data-testid": dataTestId || testID,
302
+ ...props,
303
+ children
304
+ }
305
+ );
306
+ }
307
+ );
308
+ Box.displayName = "Box";
309
+
310
+ // ../../foundation/primitives-web/src/Text.tsx
311
+ var import_styled_components2 = __toESM(require("styled-components"));
312
+
313
+ // ../../foundation/primitives-web/src/textTruncation.ts
314
+ var truncationStyles = (numberOfLines) => {
315
+ if (!numberOfLines || numberOfLines < 1) return "";
316
+ if (numberOfLines === 1) {
317
+ return `
318
+ display: block;
319
+ max-width: 100%;
320
+ min-width: 0;
321
+ overflow: hidden;
322
+ text-overflow: ellipsis;
323
+ white-space: nowrap;
324
+ `;
325
+ }
326
+ return `
327
+ display: -webkit-box;
328
+ -webkit-box-orient: vertical;
329
+ -webkit-line-clamp: ${numberOfLines};
330
+ line-clamp: ${numberOfLines};
331
+ max-width: 100%;
332
+ min-width: 0;
333
+ overflow: hidden;
334
+ `;
335
+ };
336
+
337
+ // ../../foundation/primitives-web/src/Text.tsx
338
+ var import_jsx_runtime2 = require("react/jsx-runtime");
339
+ var FilteredSpan = createFilteredElement("span");
340
+ var StyledText = (0, import_styled_components2.default)(FilteredSpan)`
341
+ color: ${(props) => props.color || "inherit"};
342
+ font-size: ${(props) => typeof props.fontSize === "number" ? `${props.fontSize}px` : props.fontSize || "inherit"};
343
+ font-weight: ${(props) => props.fontWeight || "normal"};
344
+ font-family: ${(props) => props.fontFamily || '"Aktiv Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'};
345
+ line-height: ${(props) => typeof props.lineHeight === "number" ? `${props.lineHeight}px` : props.lineHeight || "inherit"};
346
+ white-space: ${(props) => props.whiteSpace || "normal"};
347
+ text-align: ${(props) => props.textAlign || "inherit"};
348
+ text-decoration: ${(props) => props.textDecoration || "none"};
349
+
350
+ /* Keep last: single-line truncation has to win over white-space above. */
351
+ ${(props) => truncationStyles(props.numberOfLines)}
352
+ `;
353
+ var Text = ({
354
+ style,
355
+ className,
356
+ id,
357
+ role,
358
+ testID,
359
+ "data-testid": dataTestId,
360
+ ...props
361
+ }) => {
362
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
363
+ StyledText,
364
+ {
365
+ ...props,
366
+ style,
367
+ className,
368
+ id,
369
+ role,
370
+ "data-testid": dataTestId || testID
371
+ }
372
+ );
373
+ };
374
+
375
+ // ../../foundation/primitives-web/src/index.tsx
376
+ var isWeb = true;
377
+
378
+ // src/GradientPicker.tsx
379
+ var import_xui_core2 = require("@xsolla/xui-core");
380
+ var import_xui_input = require("@xsolla/xui-input");
381
+ var import_xui_input_color = require("@xsolla/xui-input-color");
382
+ var import_xui_select = require("@xsolla/xui-select");
383
+ var import_xui_button = require("@xsolla/xui-button");
384
+ var import_xui_color_picker = require("@xsolla/xui-color-picker");
385
+
386
+ // src/GradientStopMarker.tsx
387
+ var import_xui_core = require("@xsolla/xui-core");
388
+
389
+ // src/utils.ts
390
+ var MIN_POSITION = 0;
391
+ var MAX_POSITION = 100;
392
+ var clampPosition = (position) => {
393
+ if (!Number.isFinite(position)) return MIN_POSITION;
394
+ return Math.min(MAX_POSITION, Math.max(MIN_POSITION, Math.round(position)));
395
+ };
396
+ var clampOpacity = (opacity) => {
397
+ if (!Number.isFinite(opacity)) return 100;
398
+ return Math.min(100, Math.max(0, Math.round(opacity)));
399
+ };
400
+ var normalizeHex = (hex) => {
401
+ const raw = String(hex ?? "").trim().replace(/^#/, "");
402
+ if (/^[0-9a-fA-F]{3}$/.test(raw)) {
403
+ return `#${raw.split("").map((char) => char + char).join("")}`.toUpperCase();
404
+ }
405
+ if (/^[0-9a-fA-F]{6}$/.test(raw)) return `#${raw}`.toUpperCase();
406
+ if (/^[0-9a-fA-F]{8}$/.test(raw)) return `#${raw.slice(0, 6)}`.toUpperCase();
407
+ return "#000000";
408
+ };
409
+ var hexToRgb = (hex) => {
410
+ const normalized = normalizeHex(hex).slice(1);
411
+ return {
412
+ r: parseInt(normalized.slice(0, 2), 16),
413
+ g: parseInt(normalized.slice(2, 4), 16),
414
+ b: parseInt(normalized.slice(4, 6), 16)
415
+ };
416
+ };
417
+ var rgbToHex = (r, g, b) => {
418
+ const toChannel = (channel) => Math.min(255, Math.max(0, Math.round(channel))).toString(16).padStart(2, "0");
419
+ return `#${toChannel(r)}${toChannel(g)}${toChannel(b)}`.toUpperCase();
420
+ };
421
+ var sortStops = (stops) => stops.map((stop, index2) => ({ stop, index: index2 })).sort(
422
+ (a, b) => a.stop.position === b.stop.position ? a.index - b.index : a.stop.position - b.stop.position
423
+ ).map(({ stop }) => stop);
424
+ var stopToCssColor = (stop) => {
425
+ const opacity = clampOpacity(stop.opacity);
426
+ if (opacity >= 100) return normalizeHex(stop.color);
427
+ const { r, g, b } = hexToRgb(stop.color);
428
+ return `rgba(${r}, ${g}, ${b}, ${Number((opacity / 100).toFixed(2))})`;
429
+ };
430
+ var stopsToCssStopList = (stops) => {
431
+ if (stops.length === 0) return "transparent 0%, transparent 100%";
432
+ if (stops.length === 1) {
433
+ const color = stopToCssColor(stops[0]);
434
+ return `${color} 0%, ${color} 100%`;
435
+ }
436
+ return sortStops(stops).map((stop) => `${stopToCssColor(stop)} ${clampPosition(stop.position)}%`).join(", ");
437
+ };
438
+ var toCssGradient = (value) => {
439
+ const stopList = stopsToCssStopList(value.stops);
440
+ const angle = Number.isFinite(value.angle) ? Math.round(value.angle) : 0;
441
+ switch (value.type) {
442
+ case "radial":
443
+ return `radial-gradient(circle, ${stopList})`;
444
+ case "angular":
445
+ return `conic-gradient(from ${angle}deg, ${stopList})`;
446
+ case "linear":
447
+ default:
448
+ return `linear-gradient(${angle}deg, ${stopList})`;
449
+ }
450
+ };
451
+ var toPreviewCssGradient = (value) => `linear-gradient(90deg, ${stopsToCssStopList(value.stops)})`;
452
+ var supportsAngle = (value) => value === "linear" || value === "angular";
453
+ var interpolateColorAt = (stops, position) => {
454
+ if (stops.length === 0) return { color: "#000000", opacity: 100 };
455
+ const sorted = sortStops(stops);
456
+ const target = clampPosition(position);
457
+ const first = sorted[0];
458
+ if (target <= first.position) {
459
+ return {
460
+ color: normalizeHex(first.color),
461
+ opacity: clampOpacity(first.opacity)
462
+ };
463
+ }
464
+ const last = sorted[sorted.length - 1];
465
+ if (target >= last.position) {
466
+ return {
467
+ color: normalizeHex(last.color),
468
+ opacity: clampOpacity(last.opacity)
469
+ };
470
+ }
471
+ for (let index2 = 0; index2 < sorted.length - 1; index2 += 1) {
472
+ const from = sorted[index2];
473
+ const to = sorted[index2 + 1];
474
+ if (target < from.position || target > to.position) continue;
475
+ const span = to.position - from.position;
476
+ const ratio = span === 0 ? 0 : (target - from.position) / span;
477
+ const fromRgb = hexToRgb(from.color);
478
+ const toRgb = hexToRgb(to.color);
479
+ return {
480
+ color: rgbToHex(
481
+ fromRgb.r + (toRgb.r - fromRgb.r) * ratio,
482
+ fromRgb.g + (toRgb.g - fromRgb.g) * ratio,
483
+ fromRgb.b + (toRgb.b - fromRgb.b) * ratio
484
+ ),
485
+ opacity: clampOpacity(
486
+ clampOpacity(from.opacity) + (clampOpacity(to.opacity) - clampOpacity(from.opacity)) * ratio
487
+ )
488
+ };
489
+ }
490
+ return {
491
+ color: normalizeHex(last.color),
492
+ opacity: clampOpacity(last.opacity)
493
+ };
494
+ };
495
+ var createStopId = (stops) => {
496
+ const highest = stops.reduce((max, stop) => {
497
+ const match = /^stop-(\d+)$/.exec(stop.id);
498
+ return match ? Math.max(max, Number(match[1])) : max;
499
+ }, 0);
500
+ return `stop-${highest + 1}`;
501
+ };
502
+ var addStopAt = (stops, position, maxStops) => {
503
+ if (stops.length >= maxStops) return stops;
504
+ const target = clampPosition(position);
505
+ const { color, opacity } = interpolateColorAt(stops, target);
506
+ return sortStops([
507
+ ...stops,
508
+ { id: createStopId(stops), color, position: target, opacity }
509
+ ]);
510
+ };
511
+ var removeStop = (stops, id, minStops) => {
512
+ if (stops.length <= minStops) return stops;
513
+ const next = stops.filter((stop) => stop.id !== id);
514
+ return next.length === stops.length ? stops : next;
515
+ };
516
+ var updateStop = (stops, id, patch) => stops.map((stop) => {
517
+ if (stop.id !== id) return stop;
518
+ return {
519
+ ...stop,
520
+ ...patch,
521
+ color: patch.color === void 0 ? stop.color : normalizeHex(patch.color),
522
+ position: patch.position === void 0 ? stop.position : clampPosition(patch.position),
523
+ opacity: patch.opacity === void 0 ? stop.opacity : clampOpacity(patch.opacity)
524
+ };
525
+ });
526
+ var DEFAULT_GRADIENT = {
527
+ type: "linear",
528
+ angle: 0,
529
+ stops: [
530
+ { id: "stop-1", color: "#D9D9D9", position: 0, opacity: 100 },
531
+ { id: "stop-2", color: "#22A8C3", position: 100, opacity: 100 }
532
+ ]
533
+ };
534
+
535
+ // src/GradientStopMarker.tsx
536
+ var import_jsx_runtime3 = require("react/jsx-runtime");
537
+ var GradientStopMarker = ({
538
+ stop,
539
+ index: index2,
540
+ active = false,
541
+ disabled = false,
542
+ onDragStart,
543
+ onKeyDown,
544
+ themeMode,
545
+ themeProductContext
546
+ }) => {
547
+ const { theme } = (0, import_xui_core.useResolvedTheme)({ themeMode, themeProductContext });
548
+ const size = active ? 18 : 16;
549
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
550
+ Box,
551
+ {
552
+ role: "slider",
553
+ tabIndex: disabled ? -1 : 0,
554
+ "aria-label": `Stop ${index2} position`,
555
+ "aria-valuenow": stop.position,
556
+ "aria-valuemin": MIN_POSITION,
557
+ "aria-valuemax": MAX_POSITION,
558
+ "aria-valuetext": `${stop.position}%`,
559
+ "aria-orientation": "horizontal",
560
+ "aria-disabled": disabled || void 0,
561
+ testID: `gradient-stop-${stop.id}`,
562
+ "data-testid": `gradient-stop-${stop.id}`,
563
+ position: "absolute",
564
+ left: `${stop.position}%`,
565
+ width: size,
566
+ height: size,
567
+ borderRadius: 999,
568
+ zIndex: active ? 3 : 2,
569
+ cursor: disabled ? "not-allowed" : "grab",
570
+ onMouseDown: isWeb && !disabled ? onDragStart : void 0,
571
+ onKeyDown: disabled ? void 0 : onKeyDown,
572
+ style: {
573
+ top: "50%",
574
+ transform: "translate(-50%, -50%)",
575
+ boxSizing: "border-box",
576
+ borderStyle: "solid",
577
+ borderWidth: 3,
578
+ borderColor: theme.colors.background.primary,
579
+ backgroundColor: stopToCssColor(stop),
580
+ boxShadow: active ? "0px 0px 0px 2px rgba(7, 7, 8, 0.25)" : "0px 1px 2px rgba(7, 7, 8, 0.2), 0px 1px 3px 1px rgba(7, 7, 8, 0.1)",
581
+ transition: "width 0.1s ease, height 0.1s ease, box-shadow 0.1s ease",
582
+ outline: "none"
583
+ }
584
+ }
585
+ );
586
+ };
587
+ GradientStopMarker.displayName = "GradientStopMarker";
588
+
589
+ // src/icons.tsx
590
+ var import_jsx_runtime4 = require("react/jsx-runtime");
591
+ var PlusGlyph = ({
592
+ size = 18,
593
+ color = "currentColor"
594
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
595
+ "svg",
596
+ {
597
+ viewBox: "0 0 24 24",
598
+ width: size,
599
+ height: size,
600
+ fill: "none",
601
+ stroke: color,
602
+ strokeWidth: "2",
603
+ strokeLinecap: "round",
604
+ "aria-hidden": "true",
605
+ focusable: "false",
606
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 5v14M5 12h14" })
607
+ }
608
+ );
609
+ var MinusGlyph = ({
610
+ size = 18,
611
+ color = "currentColor"
612
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
613
+ "svg",
614
+ {
615
+ viewBox: "0 0 24 24",
616
+ width: size,
617
+ height: size,
618
+ fill: "none",
619
+ stroke: color,
620
+ strokeWidth: "2",
621
+ strokeLinecap: "round",
622
+ "aria-hidden": "true",
623
+ focusable: "false",
624
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 12h14" })
625
+ }
626
+ );
627
+ var AngleGlyph = ({
628
+ size = 16,
629
+ color = "currentColor"
630
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
631
+ "svg",
632
+ {
633
+ viewBox: "0 0 24 24",
634
+ width: size,
635
+ height: size,
636
+ fill: "none",
637
+ stroke: color,
638
+ strokeWidth: "2",
639
+ strokeLinecap: "round",
640
+ strokeLinejoin: "round",
641
+ "aria-hidden": "true",
642
+ focusable: "false",
643
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 20h16L4 4z" })
644
+ }
645
+ );
646
+ var PercentGlyph = ({
647
+ size = 16,
648
+ color = "currentColor"
649
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
650
+ "svg",
651
+ {
652
+ viewBox: "0 0 24 24",
653
+ width: size,
654
+ height: size,
655
+ fill: "none",
656
+ stroke: color,
657
+ strokeWidth: "2",
658
+ strokeLinecap: "round",
659
+ "aria-hidden": "true",
660
+ focusable: "false",
661
+ children: [
662
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "6.5", cy: "6.5", r: "2.5" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "17.5", cy: "17.5", r: "2.5" }),
664
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M19 5 5 19" })
665
+ ]
666
+ }
667
+ );
668
+
669
+ // src/GradientPicker.tsx
670
+ var import_jsx_runtime5 = require("react/jsx-runtime");
671
+ var DEFAULT_TYPE_LABELS = {
672
+ linear: "Linear gradient",
673
+ radial: "Radial gradient",
674
+ angular: "Angular gradient"
675
+ };
676
+ var ALL_TYPES = ["linear", "radial", "angular"];
677
+ var DRAG_OFF_THRESHOLD = 32;
678
+ var TRACK_HEIGHT = 16;
679
+ var MARKER_INSET = 9;
680
+ var toHexa = (color, opacity) => {
681
+ const alpha = Math.round(clampOpacity(opacity) / 100 * 255).toString(16).padStart(2, "0").toUpperCase();
682
+ return `${normalizeHex(color)}${alpha}`;
683
+ };
684
+ var fromHexa = (value) => {
685
+ const raw = String(value ?? "").trim().replace(/^#/, "");
686
+ if (/^[0-9a-fA-F]{8}$/.test(raw)) {
687
+ return {
688
+ color: normalizeHex(raw.slice(0, 6)),
689
+ opacity: clampOpacity(parseInt(raw.slice(6, 8), 16) / 255 * 100)
690
+ };
691
+ }
692
+ return { color: normalizeHex(raw), opacity: 100 };
693
+ };
694
+ var GradientPicker = ({
695
+ value: propValue,
696
+ defaultValue,
697
+ onChange,
698
+ gradientTypes = ALL_TYPES,
699
+ typeLabels,
700
+ minStops = 1,
701
+ maxStops = 5,
702
+ disabled = false,
703
+ typeAriaLabel = "Gradient type",
704
+ angleAriaLabel = "Gradient angle",
705
+ stopsLabel = "Stops",
706
+ testID,
707
+ themeMode,
708
+ themeProductContext
709
+ }) => {
710
+ const { theme } = (0, import_xui_core2.useResolvedTheme)({ themeMode, themeProductContext });
711
+ const contentColors = theme.colors.content;
712
+ const themeProps = { themeMode, themeProductContext };
713
+ const isControlled = propValue !== void 0;
714
+ const [innerValue, setInnerValue] = (0, import_react3.useState)(
715
+ () => propValue ?? defaultValue ?? DEFAULT_GRADIENT
716
+ );
717
+ const value = isControlled ? propValue : innerValue;
718
+ const [activeStopId, setActiveStopId] = (0, import_react3.useState)(null);
719
+ const [draggingStopId, setDraggingStopId] = (0, import_react3.useState)(null);
720
+ const trackRef = (0, import_react3.useRef)(null);
721
+ const rootRef = (0, import_react3.useRef)(null);
722
+ const stops = sortStops(value.stops);
723
+ const activeStop = stops.find((stop) => stop.id === activeStopId) ?? null;
724
+ const canAdd = !disabled && stops.length < maxStops;
725
+ const canRemove = !disabled && stops.length > minStops;
726
+ const emit = (0, import_react3.useCallback)(
727
+ (next) => {
728
+ if (!isControlled) setInnerValue(next);
729
+ onChange?.({ value: next, css: toCssGradient(next) });
730
+ },
731
+ [isControlled, onChange]
732
+ );
733
+ const patchStops = (0, import_react3.useCallback)(
734
+ (nextStops) => {
735
+ if (nextStops === value.stops) return;
736
+ emit({ ...value, stops: nextStops });
737
+ },
738
+ [emit, value]
739
+ );
740
+ const focusMarker = (0, import_react3.useCallback)((stopId) => {
741
+ if (!isWeb) return;
742
+ const node = rootRef.current?.querySelector?.(
743
+ `[data-testid="gradient-stop-${stopId}"]`
744
+ );
745
+ node?.focus?.();
746
+ }, []);
747
+ const closeColorPicker = (0, import_react3.useCallback)(() => {
748
+ const previous = activeStopId;
749
+ setActiveStopId(null);
750
+ if (previous) focusMarker(previous);
751
+ }, [activeStopId, focusMarker]);
752
+ (0, import_react3.useEffect)(() => {
753
+ if (!isWeb || !activeStopId) return void 0;
754
+ const onKey = (event) => {
755
+ if (event.key === "Escape") closeColorPicker();
756
+ };
757
+ document.addEventListener("keydown", onKey);
758
+ return () => document.removeEventListener("keydown", onKey);
759
+ }, [activeStopId, closeColorPicker]);
760
+ const positionFromClientX = (0, import_react3.useCallback)((clientX) => {
761
+ const rect = trackRef.current?.getBoundingClientRect?.();
762
+ if (!rect || !rect.width) return 0;
763
+ return clampPosition((clientX - rect.left) / rect.width * 100);
764
+ }, []);
765
+ const addStop = (position) => {
766
+ const before = value.stops;
767
+ const after = addStopAt(before, position, maxStops);
768
+ if (after === before) return;
769
+ patchStops(after);
770
+ const added = after.find(
771
+ (stop) => !before.some((existing) => existing.id === stop.id)
772
+ );
773
+ if (added) setActiveStopId(added.id);
774
+ };
775
+ const handleTrackPress = (event) => {
776
+ if (!canAdd) return;
777
+ addStop(positionFromClientX(event.clientX));
778
+ };
779
+ const handleAddStopPress = () => {
780
+ if (!canAdd) return;
781
+ const sorted = sortStops(value.stops);
782
+ let position = 50;
783
+ let widest = -1;
784
+ for (let index2 = 0; index2 < sorted.length - 1; index2 += 1) {
785
+ const gap = sorted[index2 + 1].position - sorted[index2].position;
786
+ if (gap > widest) {
787
+ widest = gap;
788
+ position = sorted[index2].position + gap / 2;
789
+ }
790
+ }
791
+ addStop(position);
792
+ };
793
+ const handleRemoveStop = (stopId) => {
794
+ const after = removeStop(value.stops, stopId, minStops);
795
+ if (after === value.stops) return;
796
+ if (activeStopId === stopId) setActiveStopId(null);
797
+ patchStops(after);
798
+ };
799
+ const handleDragStart = (stop) => (event) => {
800
+ if (disabled) return;
801
+ event.preventDefault();
802
+ event.stopPropagation();
803
+ const startY = event.clientY;
804
+ setDraggingStopId(stop.id);
805
+ setActiveStopId(stop.id);
806
+ let latest = value.stops;
807
+ let removed = false;
808
+ const onMouseMove = (moveEvent) => {
809
+ if (removed) return;
810
+ if (Math.abs(moveEvent.clientY - startY) > DRAG_OFF_THRESHOLD) {
811
+ const after = removeStop(latest, stop.id, minStops);
812
+ if (after !== latest) {
813
+ latest = after;
814
+ removed = true;
815
+ patchStops(after);
816
+ }
817
+ return;
818
+ }
819
+ latest = updateStop(latest, stop.id, {
820
+ position: positionFromClientX(moveEvent.clientX)
821
+ });
822
+ patchStops(latest);
823
+ };
824
+ const onMouseUp = () => {
825
+ setDraggingStopId(null);
826
+ if (removed) setActiveStopId(null);
827
+ document.removeEventListener("mousemove", onMouseMove);
828
+ document.removeEventListener("mouseup", onMouseUp);
829
+ };
830
+ document.addEventListener("mousemove", onMouseMove);
831
+ document.addEventListener("mouseup", onMouseUp);
832
+ };
833
+ const handleMarkerKeyDown = (stop) => (event) => {
834
+ if (disabled) return;
835
+ const step = event.shiftKey ? 10 : 1;
836
+ let handled = true;
837
+ switch (event.key) {
838
+ case "ArrowRight":
839
+ case "ArrowUp":
840
+ patchStops(
841
+ updateStop(value.stops, stop.id, { position: stop.position + step })
842
+ );
843
+ break;
844
+ case "ArrowLeft":
845
+ case "ArrowDown":
846
+ patchStops(
847
+ updateStop(value.stops, stop.id, { position: stop.position - step })
848
+ );
849
+ break;
850
+ case "Home":
851
+ patchStops(updateStop(value.stops, stop.id, { position: 0 }));
852
+ break;
853
+ case "End":
854
+ patchStops(updateStop(value.stops, stop.id, { position: 100 }));
855
+ break;
856
+ case "Enter":
857
+ case " ":
858
+ setActiveStopId((current) => current === stop.id ? null : stop.id);
859
+ break;
860
+ case "Delete":
861
+ case "Backspace":
862
+ handleRemoveStop(stop.id);
863
+ break;
864
+ default:
865
+ handled = false;
866
+ }
867
+ if (handled) event.preventDefault();
868
+ };
869
+ const typeOptions = gradientTypes.map((type) => ({
870
+ label: typeLabels?.[type] ?? DEFAULT_TYPE_LABELS[type],
871
+ value: type
872
+ }));
873
+ const showAngle = supportsAngle(value.type);
874
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
875
+ Box,
876
+ {
877
+ ref: rootRef,
878
+ testID,
879
+ "data-testid": testID,
880
+ backgroundColor: theme.colors.layer.float,
881
+ borderRadius: theme.shape.contextMenu.lg.borderRadius,
882
+ padding: 16,
883
+ gap: 12,
884
+ width: 344,
885
+ style: { boxShadow: "0px 4px 16px 0px rgba(7, 7, 8, 0.1)" },
886
+ children: [
887
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box, { flexDirection: "row", gap: 8, alignItems: "center", children: [
888
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box, { flex: 1, role: "group", "aria-label": typeAriaLabel, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
889
+ import_xui_select.Select,
890
+ {
891
+ ...themeProps,
892
+ size: "sm",
893
+ options: typeOptions,
894
+ value: value.type,
895
+ disabled,
896
+ onChange: (next) => emit({ ...value, type: next })
897
+ }
898
+ ) }),
899
+ showAngle && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box, { width: 88, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
900
+ import_xui_input.Input,
901
+ {
902
+ ...themeProps,
903
+ size: "sm",
904
+ inputMode: "numeric",
905
+ disabled,
906
+ "aria-label": angleAriaLabel,
907
+ iconLeft: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AngleGlyph, {}),
908
+ value: `${Math.round(value.angle)}`,
909
+ onChange: (event) => {
910
+ const parsed = parseInt(event.target.value, 10);
911
+ emit({
912
+ ...value,
913
+ angle: Number.isNaN(parsed) ? 0 : (parsed % 360 + 360) % 360
914
+ });
915
+ }
916
+ }
917
+ ) })
918
+ ] }),
919
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
920
+ Box,
921
+ {
922
+ height: TRACK_HEIGHT,
923
+ justifyContent: "center",
924
+ paddingHorizontal: MARKER_INSET,
925
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
926
+ Box,
927
+ {
928
+ ref: trackRef,
929
+ width: "100%",
930
+ height: TRACK_HEIGHT,
931
+ position: "relative",
932
+ cursor: canAdd ? "copy" : "default",
933
+ onMouseDown: isWeb && canAdd ? handleTrackPress : void 0,
934
+ children: [
935
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
936
+ Box,
937
+ {
938
+ testID: "gradient-track",
939
+ "data-testid": "gradient-track",
940
+ "aria-hidden": true,
941
+ position: "absolute",
942
+ width: "100%",
943
+ height: TRACK_HEIGHT,
944
+ borderRadius: 999,
945
+ style: {
946
+ top: 0,
947
+ left: 0,
948
+ backgroundImage: toPreviewCssGradient(value)
949
+ }
950
+ }
951
+ ),
952
+ stops.map((stop, index2) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
953
+ GradientStopMarker,
954
+ {
955
+ stop,
956
+ index: index2 + 1,
957
+ disabled,
958
+ active: activeStopId === stop.id || draggingStopId === stop.id,
959
+ onDragStart: handleDragStart(stop),
960
+ onKeyDown: handleMarkerKeyDown(stop),
961
+ themeMode,
962
+ themeProductContext
963
+ },
964
+ stop.id
965
+ ))
966
+ ]
967
+ }
968
+ )
969
+ }
970
+ ),
971
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
972
+ Box,
973
+ {
974
+ flexDirection: "row",
975
+ alignItems: "center",
976
+ justifyContent: "space-between",
977
+ children: [
978
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: contentColors.primary, fontSize: 14, children: stopsLabel }),
979
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
980
+ import_xui_button.IconButton,
981
+ {
982
+ ...themeProps,
983
+ size: "sm",
984
+ variant: "tertiary",
985
+ tone: "mono",
986
+ disabled: !canAdd,
987
+ onPress: handleAddStopPress,
988
+ icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PlusGlyph, {}),
989
+ "aria-label": "Add stop"
990
+ }
991
+ )
992
+ ]
993
+ }
994
+ ),
995
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box, { gap: 8, children: stops.map((stop, index2) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
996
+ Box,
997
+ {
998
+ flexDirection: "row",
999
+ alignItems: "center",
1000
+ gap: 8,
1001
+ testID: `gradient-stop-row-${stop.id}`,
1002
+ "data-testid": `gradient-stop-row-${stop.id}`,
1003
+ children: [
1004
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box, { width: 72, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1005
+ import_xui_input.Input,
1006
+ {
1007
+ ...themeProps,
1008
+ size: "sm",
1009
+ inputMode: "numeric",
1010
+ disabled,
1011
+ "aria-label": `Stop ${index2 + 1} position percent`,
1012
+ iconRight: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentGlyph, {}),
1013
+ value: `${stop.position}`,
1014
+ onChange: (event) => {
1015
+ const parsed = parseInt(event.target.value, 10);
1016
+ if (Number.isNaN(parsed)) return;
1017
+ patchStops(
1018
+ updateStop(value.stops, stop.id, { position: parsed })
1019
+ );
1020
+ }
1021
+ }
1022
+ ) }),
1023
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1024
+ import_xui_input_color.InputColor,
1025
+ {
1026
+ size: "sm",
1027
+ type: "color-hex",
1028
+ transparency: true,
1029
+ "aria-label": `Stop ${index2 + 1} colour`,
1030
+ testID: `gradient-stop-color-${stop.id}`,
1031
+ value: toHexa(stop.color, stop.opacity),
1032
+ onChange: (next) => {
1033
+ const { color, opacity } = fromHexa(next);
1034
+ patchStops(
1035
+ updateStop(value.stops, stop.id, { color, opacity })
1036
+ );
1037
+ },
1038
+ themeMode,
1039
+ themeProductContext
1040
+ }
1041
+ ) }),
1042
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1043
+ import_xui_button.IconButton,
1044
+ {
1045
+ ...themeProps,
1046
+ size: "sm",
1047
+ variant: "tertiary",
1048
+ tone: "mono",
1049
+ disabled: !canRemove,
1050
+ onPress: () => handleRemoveStop(stop.id),
1051
+ icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinusGlyph, {}),
1052
+ "aria-label": `Remove stop ${index2 + 1}`
1053
+ }
1054
+ )
1055
+ ]
1056
+ },
1057
+ stop.id
1058
+ )) }),
1059
+ activeStop && !disabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1060
+ import_xui_color_picker.ColorPicker,
1061
+ {
1062
+ alpha: true,
1063
+ colorFormat: "hex",
1064
+ value: toHexa(activeStop.color, activeStop.opacity),
1065
+ onChange: ({
1066
+ valueInInitialFormat
1067
+ }) => {
1068
+ const { color, opacity } = fromHexa(valueInInitialFormat);
1069
+ patchStops(
1070
+ updateStop(value.stops, activeStop.id, { color, opacity })
1071
+ );
1072
+ },
1073
+ themeMode,
1074
+ themeProductContext
1075
+ }
1076
+ )
1077
+ ]
1078
+ }
1079
+ );
1080
+ };
1081
+ GradientPicker.displayName = "GradientPicker";
1082
+ // Annotate the CommonJS export names for ESM import in node:
1083
+ 0 && (module.exports = {
1084
+ DEFAULT_GRADIENT,
1085
+ GradientPicker,
1086
+ GradientStopMarker,
1087
+ addStopAt,
1088
+ interpolateColorAt,
1089
+ removeStop,
1090
+ sortStops,
1091
+ supportsAngle,
1092
+ toCssGradient,
1093
+ toPreviewCssGradient,
1094
+ updateStop
1095
+ });
1096
+ //# sourceMappingURL=index.js.map