@xsolla/xui-input-color 0.184.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.mjs ADDED
@@ -0,0 +1,922 @@
1
+ // src/InputColor.tsx
2
+ import { forwardRef as forwardRef2, useEffect, useMemo, useRef, useState } from "react";
3
+
4
+ // ../../foundation/primitives-web/src/Box.tsx
5
+ import React2 from "react";
6
+ import styled from "styled-components";
7
+
8
+ // ../../foundation/primitives-web/src/filterDOMProps.ts
9
+ import React from "react";
10
+
11
+ // ../../../node_modules/@emotion/memoize/dist/memoize.esm.js
12
+ function memoize(fn) {
13
+ var cache = {};
14
+ return function(arg) {
15
+ if (cache[arg] === void 0) cache[arg] = fn(arg);
16
+ return cache[arg];
17
+ };
18
+ }
19
+ var memoize_esm_default = memoize;
20
+
21
+ // ../../../node_modules/@emotion/is-prop-valid/dist/is-prop-valid.esm.js
22
+ 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)-.*))$/;
23
+ var index = memoize_esm_default(
24
+ function(prop) {
25
+ return reactPropsRegex.test(prop) || prop.charCodeAt(0) === 111 && prop.charCodeAt(1) === 110 && prop.charCodeAt(2) < 91;
26
+ }
27
+ /* Z+1 */
28
+ );
29
+ var is_prop_valid_esm_default = index;
30
+
31
+ // ../../foundation/primitives-web/src/filterDOMProps.ts
32
+ var ADDITIONAL_BLOCKED_PROPS = /* @__PURE__ */ new Set([
33
+ // RN-only event handlers (pass isPropValid's on* pattern)
34
+ "onPress",
35
+ "onChangeText",
36
+ "onLayout",
37
+ "onMoveShouldSetResponder",
38
+ "onResponderGrant",
39
+ "onResponderMove",
40
+ "onResponderRelease",
41
+ "onResponderTerminate",
42
+ // SVG attributes that pass isPropValid
43
+ "strokeWidth",
44
+ // CSS properties that pass isPropValid but are used as component props
45
+ "overflow",
46
+ "cursor",
47
+ "fontSize",
48
+ "fontWeight",
49
+ "fontFamily",
50
+ "textDecoration"
51
+ ]);
52
+ function shouldForwardProp(key) {
53
+ if (ADDITIONAL_BLOCKED_PROPS.has(key)) return false;
54
+ return is_prop_valid_esm_default(key);
55
+ }
56
+ function createFilteredElement(defaultTag) {
57
+ const Component = React.forwardRef(
58
+ ({ children, elementType, ...props }, ref) => {
59
+ const Tag = elementType || defaultTag;
60
+ const htmlProps = {};
61
+ for (const key of Object.keys(props)) {
62
+ if (shouldForwardProp(key)) {
63
+ htmlProps[key] = props[key];
64
+ }
65
+ }
66
+ return React.createElement(
67
+ Tag,
68
+ { ref, ...htmlProps },
69
+ children
70
+ );
71
+ }
72
+ );
73
+ Component.displayName = `Filtered(${defaultTag})`;
74
+ return Component;
75
+ }
76
+
77
+ // ../../foundation/primitives-web/src/Box.tsx
78
+ import { jsx } from "react/jsx-runtime";
79
+ var FilteredDiv = createFilteredElement("div");
80
+ var StyledBox = styled(FilteredDiv)`
81
+ display: flex;
82
+ box-sizing: border-box;
83
+ background-color: ${(props) => props.backgroundColor || "transparent"};
84
+ border-color: ${(props) => props.borderColor || "transparent"};
85
+ border-width: ${(props) => typeof props.borderWidth === "number" ? `${props.borderWidth}px` : props.borderWidth || 0};
86
+
87
+ ${(props) => props.borderBottomWidth !== void 0 && `
88
+ border-bottom-width: ${typeof props.borderBottomWidth === "number" ? `${props.borderBottomWidth}px` : props.borderBottomWidth};
89
+ border-bottom-color: ${props.borderBottomColor || props.borderColor || "transparent"};
90
+ border-bottom-style: solid;
91
+ `}
92
+ ${(props) => props.borderTopWidth !== void 0 && `
93
+ border-top-width: ${typeof props.borderTopWidth === "number" ? `${props.borderTopWidth}px` : props.borderTopWidth};
94
+ border-top-color: ${props.borderTopColor || props.borderColor || "transparent"};
95
+ border-top-style: solid;
96
+ `}
97
+ ${(props) => props.borderLeftWidth !== void 0 && `
98
+ border-left-width: ${typeof props.borderLeftWidth === "number" ? `${props.borderLeftWidth}px` : props.borderLeftWidth};
99
+ border-left-color: ${props.borderLeftColor || props.borderColor || "transparent"};
100
+ border-left-style: solid;
101
+ `}
102
+ ${(props) => props.borderRightWidth !== void 0 && `
103
+ border-right-width: ${typeof props.borderRightWidth === "number" ? `${props.borderRightWidth}px` : props.borderRightWidth};
104
+ border-right-color: ${props.borderRightColor || props.borderColor || "transparent"};
105
+ border-right-style: solid;
106
+ `}
107
+
108
+ border-style: ${(props) => props.borderStyle || (props.borderWidth || props.borderBottomWidth || props.borderTopWidth || props.borderLeftWidth || props.borderRightWidth ? "solid" : "none")};
109
+ border-radius: ${(props) => typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius || 0};
110
+ height: ${(props) => typeof props.height === "number" ? `${props.height}px` : props.height || "auto"};
111
+ width: ${(props) => typeof props.width === "number" ? `${props.width}px` : props.width || "auto"};
112
+ min-width: ${(props) => typeof props.minWidth === "number" ? `${props.minWidth}px` : props.minWidth || "auto"};
113
+ min-height: ${(props) => typeof props.minHeight === "number" ? `${props.minHeight}px` : props.minHeight || "auto"};
114
+ max-width: ${(props) => typeof props.maxWidth === "number" ? `${props.maxWidth}px` : props.maxWidth || "none"};
115
+ max-height: ${(props) => typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight || "none"};
116
+
117
+ padding: ${(props) => typeof props.padding === "number" ? `${props.padding}px` : props.padding || 0};
118
+ ${(props) => props.paddingHorizontal && `
119
+ padding-left: ${typeof props.paddingHorizontal === "number" ? `${props.paddingHorizontal}px` : props.paddingHorizontal};
120
+ padding-right: ${typeof props.paddingHorizontal === "number" ? `${props.paddingHorizontal}px` : props.paddingHorizontal};
121
+ `}
122
+ ${(props) => props.paddingVertical && `
123
+ padding-top: ${typeof props.paddingVertical === "number" ? `${props.paddingVertical}px` : props.paddingVertical};
124
+ padding-bottom: ${typeof props.paddingVertical === "number" ? `${props.paddingVertical}px` : props.paddingVertical};
125
+ `}
126
+ ${(props) => props.paddingTop !== void 0 && `padding-top: ${typeof props.paddingTop === "number" ? `${props.paddingTop}px` : props.paddingTop};`}
127
+ ${(props) => props.paddingBottom !== void 0 && `padding-bottom: ${typeof props.paddingBottom === "number" ? `${props.paddingBottom}px` : props.paddingBottom};`}
128
+ ${(props) => props.paddingLeft !== void 0 && `padding-left: ${typeof props.paddingLeft === "number" ? `${props.paddingLeft}px` : props.paddingLeft};`}
129
+ ${(props) => props.paddingRight !== void 0 && `padding-right: ${typeof props.paddingRight === "number" ? `${props.paddingRight}px` : props.paddingRight};`}
130
+
131
+ margin: ${(props) => typeof props.margin === "number" ? `${props.margin}px` : props.margin || 0};
132
+ ${(props) => props.marginTop !== void 0 && `margin-top: ${typeof props.marginTop === "number" ? `${props.marginTop}px` : props.marginTop};`}
133
+ ${(props) => props.marginBottom !== void 0 && `margin-bottom: ${typeof props.marginBottom === "number" ? `${props.marginBottom}px` : props.marginBottom};`}
134
+ ${(props) => props.marginLeft !== void 0 && `margin-left: ${typeof props.marginLeft === "number" ? `${props.marginLeft}px` : props.marginLeft};`}
135
+ ${(props) => props.marginRight !== void 0 && `margin-right: ${typeof props.marginRight === "number" ? `${props.marginRight}px` : props.marginRight};`}
136
+
137
+ flex-direction: ${(props) => props.flexDirection || "column"};
138
+ flex-wrap: ${(props) => props.flexWrap || "nowrap"};
139
+ align-items: ${(props) => props.alignItems || "stretch"};
140
+ justify-content: ${(props) => props.justifyContent || "flex-start"};
141
+ cursor: ${(props) => props.cursor ? props.cursor : props.onClick || props.onPress ? "pointer" : "inherit"};
142
+ position: ${(props) => props.position || "static"};
143
+ top: ${(props) => typeof props.top === "number" ? `${props.top}px` : props.top};
144
+ bottom: ${(props) => typeof props.bottom === "number" ? `${props.bottom}px` : props.bottom};
145
+ left: ${(props) => typeof props.left === "number" ? `${props.left}px` : props.left};
146
+ right: ${(props) => typeof props.right === "number" ? `${props.right}px` : props.right};
147
+ flex: ${(props) => props.flex};
148
+ flex-shrink: ${(props) => props.flexShrink ?? 1};
149
+ gap: ${(props) => typeof props.gap === "number" ? `${props.gap}px` : props.gap || 0};
150
+ align-self: ${(props) => props.alignSelf || "auto"};
151
+ overflow: ${(props) => props.overflow || "visible"};
152
+ overflow-x: ${(props) => props.overflowX || "visible"};
153
+ overflow-y: ${(props) => props.overflowY || "visible"};
154
+ z-index: ${(props) => props.zIndex};
155
+ opacity: ${(props) => props.disabled ? 0.5 : 1};
156
+ pointer-events: ${(props) => props.disabled ? "none" : "auto"};
157
+
158
+ &:hover {
159
+ ${(props) => props.hoverStyle?.backgroundColor && `background-color: ${props.hoverStyle.backgroundColor};`}
160
+ ${(props) => props.hoverStyle?.borderColor && `border-color: ${props.hoverStyle.borderColor};`}
161
+ }
162
+
163
+ &:active {
164
+ ${(props) => props.pressStyle?.backgroundColor && `background-color: ${props.pressStyle.backgroundColor};`}
165
+ }
166
+ `;
167
+ var Box = React2.forwardRef(
168
+ ({
169
+ children,
170
+ onPress,
171
+ onKeyDown,
172
+ onKeyUp,
173
+ role,
174
+ "aria-label": ariaLabel,
175
+ "aria-labelledby": ariaLabelledBy,
176
+ "aria-current": ariaCurrent,
177
+ "aria-disabled": ariaDisabled,
178
+ "aria-live": ariaLive,
179
+ "aria-busy": ariaBusy,
180
+ "aria-describedby": ariaDescribedBy,
181
+ "aria-expanded": ariaExpanded,
182
+ "aria-haspopup": ariaHasPopup,
183
+ "aria-pressed": ariaPressed,
184
+ "aria-controls": ariaControls,
185
+ tabIndex,
186
+ as,
187
+ src,
188
+ alt,
189
+ onError,
190
+ onLoad,
191
+ type,
192
+ disabled,
193
+ id,
194
+ testID,
195
+ "data-testid": dataTestId,
196
+ ...props
197
+ }, ref) => {
198
+ if (as === "img" && src) {
199
+ return /* @__PURE__ */ jsx(
200
+ "img",
201
+ {
202
+ src,
203
+ alt: alt || "",
204
+ onError,
205
+ onLoad,
206
+ style: {
207
+ display: "block",
208
+ objectFit: "cover",
209
+ width: typeof props.width === "number" ? `${props.width}px` : props.width,
210
+ height: typeof props.height === "number" ? `${props.height}px` : props.height,
211
+ borderRadius: typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius,
212
+ position: props.position,
213
+ top: typeof props.top === "number" ? `${props.top}px` : props.top,
214
+ left: typeof props.left === "number" ? `${props.left}px` : props.left,
215
+ right: typeof props.right === "number" ? `${props.right}px` : props.right,
216
+ bottom: typeof props.bottom === "number" ? `${props.bottom}px` : props.bottom,
217
+ ...props.style
218
+ }
219
+ }
220
+ );
221
+ }
222
+ return /* @__PURE__ */ jsx(
223
+ StyledBox,
224
+ {
225
+ ref,
226
+ elementType: as,
227
+ id,
228
+ type: as === "button" ? type || "button" : void 0,
229
+ disabled: as === "button" ? disabled : void 0,
230
+ onClick: onPress,
231
+ onKeyDown,
232
+ onKeyUp,
233
+ role,
234
+ "aria-label": ariaLabel,
235
+ "aria-labelledby": ariaLabelledBy,
236
+ "aria-current": ariaCurrent,
237
+ "aria-disabled": ariaDisabled,
238
+ "aria-busy": ariaBusy,
239
+ "aria-describedby": ariaDescribedBy,
240
+ "aria-expanded": ariaExpanded,
241
+ "aria-haspopup": ariaHasPopup,
242
+ "aria-pressed": ariaPressed,
243
+ "aria-controls": ariaControls,
244
+ "aria-live": ariaLive,
245
+ tabIndex: tabIndex !== void 0 ? tabIndex : void 0,
246
+ "data-testid": dataTestId || testID,
247
+ ...props,
248
+ children
249
+ }
250
+ );
251
+ }
252
+ );
253
+ Box.displayName = "Box";
254
+
255
+ // ../../foundation/primitives-web/src/Text.tsx
256
+ import styled2 from "styled-components";
257
+ import { jsx as jsx2 } from "react/jsx-runtime";
258
+ var FilteredSpan = createFilteredElement("span");
259
+ var StyledText = styled2(FilteredSpan)`
260
+ color: ${(props) => props.color || "inherit"};
261
+ font-size: ${(props) => typeof props.fontSize === "number" ? `${props.fontSize}px` : props.fontSize || "inherit"};
262
+ font-weight: ${(props) => props.fontWeight || "normal"};
263
+ font-family: ${(props) => props.fontFamily || '"Aktiv Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'};
264
+ line-height: ${(props) => typeof props.lineHeight === "number" ? `${props.lineHeight}px` : props.lineHeight || "inherit"};
265
+ white-space: ${(props) => props.whiteSpace || "normal"};
266
+ text-align: ${(props) => props.textAlign || "inherit"};
267
+ text-decoration: ${(props) => props.textDecoration || "none"};
268
+ `;
269
+ var Text = ({
270
+ style,
271
+ className,
272
+ id,
273
+ role,
274
+ testID,
275
+ "data-testid": dataTestId,
276
+ numberOfLines: _numberOfLines,
277
+ ...props
278
+ }) => {
279
+ return /* @__PURE__ */ jsx2(
280
+ StyledText,
281
+ {
282
+ ...props,
283
+ style,
284
+ className,
285
+ id,
286
+ role,
287
+ "data-testid": dataTestId || testID
288
+ }
289
+ );
290
+ };
291
+
292
+ // ../../foundation/primitives-web/src/Input.tsx
293
+ import { forwardRef } from "react";
294
+ import styled3 from "styled-components";
295
+ import { jsx as jsx3 } from "react/jsx-runtime";
296
+ var FilteredInput = createFilteredElement("input");
297
+ var StyledInput = styled3(FilteredInput)`
298
+ background: transparent;
299
+ border: none;
300
+ outline: none;
301
+ width: 100%;
302
+ height: 100%;
303
+ padding: 0;
304
+ margin: 0;
305
+ color: ${(props) => props.color || "inherit"};
306
+ font-size: ${(props) => typeof props.fontSize === "number" ? `${props.fontSize}px` : props.fontSize || "inherit"};
307
+ font-family: ${(props) => props.fontFamily || '"Aktiv Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'};
308
+ text-align: inherit;
309
+
310
+ &::placeholder {
311
+ color: ${(props) => props.placeholderTextColor || "rgba(255, 255, 255, 0.5)"};
312
+ }
313
+
314
+ &:disabled {
315
+ cursor: not-allowed;
316
+ }
317
+
318
+ /* Override browser autofill background */
319
+ &:-webkit-autofill,
320
+ &:-webkit-autofill:hover,
321
+ &:-webkit-autofill:focus,
322
+ &:-webkit-autofill:active {
323
+ -webkit-box-shadow: 0 0 0 1000px transparent inset !important;
324
+ -webkit-background-clip: text !important;
325
+ -webkit-text-fill-color: ${(props) => props.color || "inherit"} !important;
326
+ }
327
+ `;
328
+ var InputPrimitive = forwardRef(
329
+ ({
330
+ value,
331
+ placeholder,
332
+ onChange,
333
+ onChangeText,
334
+ onFocus,
335
+ onBlur,
336
+ onKeyDown,
337
+ disabled,
338
+ secureTextEntry,
339
+ style,
340
+ color,
341
+ fontSize,
342
+ fontFamily,
343
+ placeholderTextColor,
344
+ maxLength,
345
+ name,
346
+ type,
347
+ inputMode,
348
+ autoComplete,
349
+ id,
350
+ "aria-invalid": ariaInvalid,
351
+ "aria-describedby": ariaDescribedBy,
352
+ "aria-labelledby": ariaLabelledBy,
353
+ "aria-label": ariaLabel,
354
+ "aria-disabled": ariaDisabled,
355
+ "data-testid": dataTestId,
356
+ testID,
357
+ ...rest
358
+ }, ref) => {
359
+ const handleChange = (e) => {
360
+ if (onChange) {
361
+ onChange(e);
362
+ }
363
+ if (onChangeText) {
364
+ onChangeText(e.target.value);
365
+ }
366
+ };
367
+ const inputValue = value !== void 0 ? value : "";
368
+ return /* @__PURE__ */ jsx3(
369
+ StyledInput,
370
+ {
371
+ ref,
372
+ id,
373
+ value: inputValue,
374
+ name,
375
+ placeholder,
376
+ onChange: handleChange,
377
+ onFocus,
378
+ onBlur,
379
+ onKeyDown,
380
+ disabled,
381
+ type: secureTextEntry ? "password" : type || "text",
382
+ inputMode,
383
+ autoComplete,
384
+ style,
385
+ color,
386
+ fontSize,
387
+ fontFamily,
388
+ placeholderTextColor,
389
+ maxLength,
390
+ "aria-invalid": ariaInvalid,
391
+ "aria-describedby": ariaDescribedBy,
392
+ "aria-labelledby": ariaLabelledBy,
393
+ "aria-label": ariaLabel,
394
+ "aria-disabled": ariaDisabled,
395
+ "data-testid": dataTestId || testID,
396
+ ...rest
397
+ }
398
+ );
399
+ }
400
+ );
401
+ InputPrimitive.displayName = "InputPrimitive";
402
+
403
+ // ../../foundation/primitives-web/src/index.tsx
404
+ var isWeb = true;
405
+
406
+ // src/InputColor.tsx
407
+ import {
408
+ useResolvedTheme,
409
+ useId
410
+ } from "@xsolla/xui-core";
411
+ import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
412
+ var clamp = (n, min, max) => Math.min(Math.max(n, min), max);
413
+ var HEX_CHARS = /[^0-9a-fA-F]/g;
414
+ function hexToRgba(hex) {
415
+ let h = (hex || "").replace(/^#/, "");
416
+ if (h.length === 3 || h.length === 4) {
417
+ h = h.split("").map((c) => c + c).join("");
418
+ }
419
+ const r = parseInt(h.slice(0, 2), 16);
420
+ const g = parseInt(h.slice(2, 4), 16);
421
+ const b = parseInt(h.slice(4, 6), 16);
422
+ const a = h.length >= 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;
423
+ return {
424
+ r: Number.isNaN(r) ? 0 : r,
425
+ g: Number.isNaN(g) ? 0 : g,
426
+ b: Number.isNaN(b) ? 0 : b,
427
+ a: Number.isNaN(a) ? 1 : parseFloat(a.toFixed(2))
428
+ };
429
+ }
430
+ function rgbaToHex({ r, g, b, a }, includeAlpha) {
431
+ const toHex = (n) => Math.round(clamp(n, 0, 255)).toString(16).padStart(2, "0");
432
+ const alpha = includeAlpha ? toHex(clamp(a, 0, 1) * 255) : "";
433
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}${alpha}`.toUpperCase();
434
+ }
435
+ var SWATCH_SIZE = {
436
+ xl: 36,
437
+ lg: 32,
438
+ md: 26,
439
+ sm: 20,
440
+ xs: 14
441
+ };
442
+ var ALPHA_WIDTH = {
443
+ xl: 96,
444
+ lg: 86,
445
+ md: 77,
446
+ sm: 67,
447
+ xs: 58
448
+ };
449
+ var FRAME_GAP = {
450
+ xl: 10,
451
+ lg: 10,
452
+ md: 8,
453
+ sm: 6,
454
+ xs: 4
455
+ };
456
+ var CHECKERBOARD = "conic-gradient(rgba(0,0,0,0.45) 25%, transparent 0 50%, rgba(0,0,0,0.45) 0 75%, transparent 0)";
457
+ function cornerRadii(corner, radius) {
458
+ const map = {
459
+ all: [radius, radius, radius, radius],
460
+ left: [radius, 0, 0, radius],
461
+ right: [0, radius, radius, 0],
462
+ middle: [0, 0, 0, 0]
463
+ };
464
+ const [tl, tr, br, bl] = map[corner];
465
+ return {
466
+ borderTopLeftRadius: tl,
467
+ borderTopRightRadius: tr,
468
+ borderBottomRightRadius: br,
469
+ borderBottomLeftRadius: bl
470
+ };
471
+ }
472
+ function ColorSwatch({
473
+ size,
474
+ rgba,
475
+ transparency,
476
+ borderColor
477
+ }) {
478
+ const solid = `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`;
479
+ const withAlpha = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`;
480
+ return /* @__PURE__ */ jsxs(
481
+ Box,
482
+ {
483
+ width: size,
484
+ height: size,
485
+ position: "relative",
486
+ borderColor,
487
+ borderWidth: 1,
488
+ style: { borderRadius: 4, overflow: "hidden" },
489
+ "data-testid": "input-color__swatch-preview",
490
+ children: [
491
+ transparency && /* @__PURE__ */ jsx4(
492
+ Box,
493
+ {
494
+ "aria-hidden": true,
495
+ style: {
496
+ position: "absolute",
497
+ inset: 0,
498
+ backgroundImage: CHECKERBOARD,
499
+ backgroundSize: "8px 8px",
500
+ opacity: 0.2
501
+ }
502
+ }
503
+ ),
504
+ transparency ? /* @__PURE__ */ jsxs(Fragment, { children: [
505
+ /* @__PURE__ */ jsx4(
506
+ Box,
507
+ {
508
+ style: {
509
+ position: "absolute",
510
+ top: 0,
511
+ bottom: 0,
512
+ left: 0,
513
+ right: "50%",
514
+ backgroundColor: solid
515
+ }
516
+ }
517
+ ),
518
+ /* @__PURE__ */ jsx4(
519
+ Box,
520
+ {
521
+ style: {
522
+ position: "absolute",
523
+ top: 0,
524
+ bottom: 0,
525
+ left: "50%",
526
+ right: 0,
527
+ backgroundColor: withAlpha
528
+ }
529
+ }
530
+ )
531
+ ] }) : /* @__PURE__ */ jsx4(
532
+ Box,
533
+ {
534
+ style: { position: "absolute", inset: 0, backgroundColor: solid }
535
+ }
536
+ )
537
+ ]
538
+ }
539
+ );
540
+ }
541
+ function TextField({
542
+ value,
543
+ onCommit,
544
+ sanitize,
545
+ maxLength,
546
+ textAlign = "left",
547
+ color,
548
+ fontSize,
549
+ fontFamily,
550
+ ariaLabel,
551
+ inputMode = "text",
552
+ step,
553
+ testID,
554
+ onFocus,
555
+ onBlur
556
+ }) {
557
+ const [text, setText] = useState(value);
558
+ const isFocusedRef = useRef(false);
559
+ useEffect(() => {
560
+ if (!isFocusedRef.current) setText(value);
561
+ }, [value]);
562
+ const handleChange = (e) => {
563
+ const next = sanitize(e.target.value);
564
+ setText(next);
565
+ onCommit(next);
566
+ };
567
+ const handleFocus = () => {
568
+ isFocusedRef.current = true;
569
+ onFocus();
570
+ };
571
+ const handleBlur = () => {
572
+ isFocusedRef.current = false;
573
+ setText(value);
574
+ onBlur();
575
+ };
576
+ const handleKeyDown = (e) => {
577
+ if (e.key === "Enter") {
578
+ e.currentTarget.blur();
579
+ return;
580
+ }
581
+ if (step && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
582
+ e.preventDefault();
583
+ const current = Number.parseInt(text, 10);
584
+ const base = Number.isNaN(current) ? 0 : current;
585
+ const next = String(
586
+ clamp(base + (e.key === "ArrowUp" ? 1 : -1), step.min, step.max)
587
+ );
588
+ setText(next);
589
+ onCommit(next);
590
+ }
591
+ };
592
+ return /* @__PURE__ */ jsx4(Box, { flex: 1, height: "100%", justifyContent: "center", children: /* @__PURE__ */ jsx4(
593
+ InputPrimitive,
594
+ {
595
+ value: text,
596
+ onChange: handleChange,
597
+ onFocus: handleFocus,
598
+ onBlur: handleBlur,
599
+ onKeyDown: handleKeyDown,
600
+ type: "text",
601
+ inputMode,
602
+ maxLength,
603
+ color,
604
+ fontSize,
605
+ fontFamily,
606
+ "aria-label": ariaLabel,
607
+ "data-testid": testID,
608
+ style: textAlign === "center" ? { textAlign: "center" } : void 0
609
+ }
610
+ ) });
611
+ }
612
+ var CHANNEL_LABEL = {
613
+ red: "Red channel",
614
+ green: "Green channel",
615
+ blue: "Blue channel",
616
+ alpha: "Opacity percentage"
617
+ };
618
+ var InputColor = forwardRef2(
619
+ ({
620
+ value,
621
+ defaultValue,
622
+ onChange,
623
+ onSwatchClick,
624
+ type = "color-hex",
625
+ transparency = false,
626
+ size = "md",
627
+ label,
628
+ id: providedId,
629
+ "aria-label": ariaLabel,
630
+ testID,
631
+ themeMode,
632
+ themeProductContext
633
+ }, ref) => {
634
+ const { theme } = useResolvedTheme({ themeMode, themeProductContext });
635
+ const [internalValue, setInternalValue] = useState(
636
+ value ?? defaultValue ?? "#000000"
637
+ );
638
+ useEffect(() => {
639
+ if (value !== void 0) setInternalValue(value);
640
+ }, [value]);
641
+ const currentValue = internalValue;
642
+ const [focusedKey, setFocusedKey] = useState(null);
643
+ const [liveMessage, setLiveMessage] = useState("");
644
+ const rawId = useId();
645
+ const safeId = rawId.replace(/:/g, "");
646
+ const inputId = providedId || `input-color-${safeId}`;
647
+ const labelId = `${inputId}-label`;
648
+ const rgba = useMemo(() => hexToRgba(currentValue), [currentValue]);
649
+ const sizeStyles = theme.sizing.input(size);
650
+ const inputColors = theme.colors.control.input;
651
+ const borderRadius = theme.shape.input[size].borderRadius;
652
+ const swatchSize = SWATCH_SIZE[size];
653
+ const showSwatch = type === "color" || type === "color-hex" || type === "color-rgb";
654
+ const isHex = type === "hex" || type === "color-hex";
655
+ const isRgb = type === "rgb" || type === "color-rgb";
656
+ const isSwatchOnly = type === "color";
657
+ const textColor = inputColors.text;
658
+ const placeholderColor = inputColors.placeholder;
659
+ const fontFamily = theme.fonts.body;
660
+ const emit = (next) => {
661
+ setInternalValue(next);
662
+ setLiveMessage(`Color updated to ${next}`);
663
+ onChange?.(next);
664
+ };
665
+ const emitFromRgba = (next) => emit(rgbaToHex(next, transparency));
666
+ const segmentVisuals = (focused) => {
667
+ let backgroundColor = inputColors.bg;
668
+ let borderColor = inputColors.border;
669
+ let outlineColor;
670
+ if (focused) {
671
+ backgroundColor = theme.colors.control.focus.bg;
672
+ outlineColor = theme.colors.border.brand;
673
+ }
674
+ return { backgroundColor, borderColor, outlineColor };
675
+ };
676
+ const renderSegment = (key, corner, content, opts = {}) => {
677
+ const focused = focusedKey === key;
678
+ const { backgroundColor, borderColor, outlineColor } = segmentVisuals(focused);
679
+ const width = opts.square ? sizeStyles.height : opts.width;
680
+ return /* @__PURE__ */ jsx4(
681
+ Box,
682
+ {
683
+ backgroundColor,
684
+ borderColor,
685
+ borderWidth: 1,
686
+ height: sizeStyles.height,
687
+ width,
688
+ flex: opts.flex,
689
+ flexDirection: "row",
690
+ alignItems: "center",
691
+ justifyContent: opts.square ? "center" : "flex-start",
692
+ gap: FRAME_GAP[size],
693
+ paddingHorizontal: opts.square ? 0 : sizeStyles.paddingHorizontal,
694
+ position: "relative",
695
+ style: {
696
+ ...cornerRadii(corner, borderRadius),
697
+ minWidth: opts.square ? void 0 : 40,
698
+ ...outlineColor && isWeb ? { outline: `1px solid ${outlineColor}`, outlineOffset: "-1px" } : outlineColor && !isWeb ? { borderColor: outlineColor } : {}
699
+ },
700
+ hoverStyle: !focused ? {
701
+ backgroundColor: inputColors.bgHover,
702
+ borderColor: inputColors.borderHover
703
+ } : void 0,
704
+ children: content
705
+ },
706
+ key
707
+ );
708
+ };
709
+ const swatchVisual = /* @__PURE__ */ jsx4(
710
+ ColorSwatch,
711
+ {
712
+ size: swatchSize,
713
+ rgba,
714
+ transparency,
715
+ borderColor: theme.colors.border.secondary
716
+ }
717
+ );
718
+ const swatchNode = isSwatchOnly ? /* @__PURE__ */ jsx4(
719
+ Box,
720
+ {
721
+ as: "button",
722
+ type: "button",
723
+ onPress: () => onSwatchClick?.(),
724
+ cursor: "pointer",
725
+ backgroundColor: "transparent",
726
+ borderWidth: 0,
727
+ padding: 0,
728
+ alignItems: "center",
729
+ justifyContent: "center",
730
+ "aria-label": "Open color picker",
731
+ "data-testid": "input-color__swatch",
732
+ onFocus: () => setFocusedKey("swatch"),
733
+ onBlur: () => setFocusedKey(null),
734
+ children: swatchVisual
735
+ }
736
+ ) : /* @__PURE__ */ jsx4(
737
+ Box,
738
+ {
739
+ "aria-hidden": true,
740
+ alignItems: "center",
741
+ justifyContent: "center",
742
+ "data-testid": "input-color__swatch-decorative",
743
+ children: swatchVisual
744
+ }
745
+ );
746
+ const hexContent = /* @__PURE__ */ jsxs(Fragment, { children: [
747
+ /* @__PURE__ */ jsx4(
748
+ Text,
749
+ {
750
+ color: placeholderColor,
751
+ fontSize: sizeStyles.fontSize,
752
+ style: { lineHeight: `${sizeStyles.lineHeight}px` },
753
+ children: "#"
754
+ }
755
+ ),
756
+ /* @__PURE__ */ jsx4(
757
+ TextField,
758
+ {
759
+ value: rgbaToHex(rgba, false).replace(/^#/, ""),
760
+ sanitize: (t) => t.replace(HEX_CHARS, "").toUpperCase(),
761
+ maxLength: 6,
762
+ onCommit: (digits) => {
763
+ if (digits.length === 3 || digits.length === 6) {
764
+ const next = hexToRgba(`#${digits}`);
765
+ emitFromRgba({ ...next, a: rgba.a });
766
+ }
767
+ },
768
+ color: textColor,
769
+ fontSize: sizeStyles.fontSize,
770
+ fontFamily,
771
+ ariaLabel: "Hex color value",
772
+ testID: "input-color__hex",
773
+ onFocus: () => setFocusedKey("hex"),
774
+ onBlur: () => setFocusedKey(null)
775
+ }
776
+ )
777
+ ] });
778
+ const channelContent = (channel) => {
779
+ const isAlpha = channel === "alpha";
780
+ const display = isAlpha ? Math.round(rgba.a * 100) : rgba[channel[0]];
781
+ const field = /* @__PURE__ */ jsx4(
782
+ TextField,
783
+ {
784
+ value: String(display),
785
+ inputMode: "numeric",
786
+ sanitize: (t) => t.replace(/[^0-9]/g, ""),
787
+ maxLength: 3,
788
+ step: isAlpha ? { min: 0, max: 100 } : { min: 0, max: 255 },
789
+ onCommit: (t) => {
790
+ if (t === "") return;
791
+ const num = parseInt(t, 10);
792
+ if (Number.isNaN(num)) return;
793
+ if (isAlpha) {
794
+ emitFromRgba({ ...rgba, a: clamp(num, 0, 100) / 100 });
795
+ } else {
796
+ const k = channel[0];
797
+ emitFromRgba({ ...rgba, [k]: clamp(num, 0, 255) });
798
+ }
799
+ },
800
+ color: textColor,
801
+ fontSize: sizeStyles.fontSize,
802
+ fontFamily,
803
+ ariaLabel: CHANNEL_LABEL[channel],
804
+ testID: `input-color__channel-${channel}`,
805
+ onFocus: () => setFocusedKey(`channel-${channel}`),
806
+ onBlur: () => setFocusedKey(null)
807
+ }
808
+ );
809
+ if (!isAlpha) return field;
810
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
811
+ field,
812
+ /* @__PURE__ */ jsx4(
813
+ Text,
814
+ {
815
+ color: placeholderColor,
816
+ fontSize: sizeStyles.fontSize,
817
+ style: { lineHeight: `${sizeStyles.lineHeight}px` },
818
+ children: "%"
819
+ }
820
+ )
821
+ ] });
822
+ };
823
+ const cells = [];
824
+ if (isSwatchOnly) {
825
+ cells.push({ key: "swatch", content: swatchNode, square: true });
826
+ } else if (isHex) {
827
+ cells.push({
828
+ key: "field",
829
+ flex: 1,
830
+ content: /* @__PURE__ */ jsxs(Fragment, { children: [
831
+ showSwatch && swatchNode,
832
+ /* @__PURE__ */ jsx4(Box, { flex: 1, flexDirection: "row", alignItems: "center", gap: 4, children: hexContent })
833
+ ] })
834
+ });
835
+ } else if (isRgb) {
836
+ if (showSwatch) {
837
+ cells.push({ key: "swatch", content: swatchNode, square: true });
838
+ }
839
+ ["red", "green", "blue"].forEach(
840
+ (channel) => cells.push({
841
+ key: `channel-${channel}`,
842
+ content: channelContent(channel),
843
+ flex: 1
844
+ })
845
+ );
846
+ }
847
+ if (transparency) {
848
+ cells.push({
849
+ key: "channel-alpha",
850
+ content: channelContent("alpha"),
851
+ width: ALPHA_WIDTH[size]
852
+ });
853
+ }
854
+ const control = cells.map((cell, i) => {
855
+ const corner = cells.length === 1 ? "all" : i === 0 ? "left" : i === cells.length - 1 ? "right" : "middle";
856
+ return renderSegment(cell.key, corner, cell.content, {
857
+ flex: cell.flex,
858
+ width: cell.width,
859
+ square: cell.square
860
+ });
861
+ });
862
+ return /* @__PURE__ */ jsxs(
863
+ Box,
864
+ {
865
+ ref,
866
+ flexDirection: "column",
867
+ gap: sizeStyles.fieldGap,
868
+ width: isSwatchOnly ? void 0 : "100%",
869
+ testID,
870
+ children: [
871
+ label && /* @__PURE__ */ jsx4(Box, { as: "label", id: labelId, children: /* @__PURE__ */ jsx4(
872
+ Text,
873
+ {
874
+ color: theme.colors.content.secondary,
875
+ fontSize: sizeStyles.fontSize - 2,
876
+ fontWeight: "500",
877
+ children: label
878
+ }
879
+ ) }),
880
+ /* @__PURE__ */ jsx4(
881
+ Box,
882
+ {
883
+ flexDirection: "row",
884
+ alignItems: "center",
885
+ gap: 2,
886
+ width: isSwatchOnly ? void 0 : "100%",
887
+ role: "group",
888
+ "aria-labelledby": label ? labelId : void 0,
889
+ "aria-label": !label ? ariaLabel : void 0,
890
+ children: control
891
+ }
892
+ ),
893
+ isWeb && /* @__PURE__ */ jsx4(
894
+ Box,
895
+ {
896
+ role: "status",
897
+ "aria-live": "polite",
898
+ "data-testid": "input-color__live",
899
+ style: {
900
+ position: "absolute",
901
+ width: 1,
902
+ height: 1,
903
+ padding: 0,
904
+ margin: -1,
905
+ overflow: "hidden",
906
+ clip: "rect(0 0 0 0)",
907
+ whiteSpace: "nowrap",
908
+ border: 0
909
+ },
910
+ children: liveMessage
911
+ }
912
+ )
913
+ ]
914
+ }
915
+ );
916
+ }
917
+ );
918
+ InputColor.displayName = "InputColor";
919
+ export {
920
+ InputColor
921
+ };
922
+ //# sourceMappingURL=index.mjs.map