astrum-ui 0.1.1

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/dist/index.mjs ADDED
@@ -0,0 +1,1216 @@
1
+ "use client";
2
+
3
+ // src/Button/Button.tsx
4
+ import * as React from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ var variantStyles = {
7
+ primary: "astrum-btn-primary",
8
+ outlined: "astrum-btn-outlined",
9
+ dashed: "astrum-btn-dashed",
10
+ grey: "astrum-btn-grey",
11
+ white: "astrum-btn-white",
12
+ ghost: "astrum-btn-ghost"
13
+ };
14
+ var sizeStyles = {
15
+ s: "astrum-btn-s",
16
+ m: "astrum-btn-m",
17
+ l: "astrum-btn-l"
18
+ };
19
+ var shapeStyles = {
20
+ default: "",
21
+ square: "astrum-btn-shape-square",
22
+ circle: "astrum-btn-shape-circle"
23
+ };
24
+ var Button = React.forwardRef(
25
+ ({
26
+ variant = "primary",
27
+ size = "m",
28
+ icon,
29
+ iconPosition = "right",
30
+ shape = "default",
31
+ className = "",
32
+ children,
33
+ ...rest
34
+ }, ref) => {
35
+ const iconOnly = icon != null && (children == null || children === "");
36
+ const effectiveShape = iconOnly && shape !== "default" ? shape : "default";
37
+ const classes = [
38
+ "astrum-btn",
39
+ variantStyles[variant],
40
+ sizeStyles[size],
41
+ shapeStyles[effectiveShape],
42
+ iconOnly ? "astrum-btn-icon-only" : "",
43
+ className
44
+ ].filter(Boolean).join(" ");
45
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
46
+ icon && iconPosition === "left" && /* @__PURE__ */ jsx("span", { className: "astrum-btn-icon", children: icon }),
47
+ children != null && children !== "" && /* @__PURE__ */ jsx("span", { className: "astrum-btn-text", children }),
48
+ icon && iconPosition === "right" && /* @__PURE__ */ jsx("span", { className: "astrum-btn-icon", children: icon })
49
+ ] });
50
+ return /* @__PURE__ */ jsx("button", { ref, className: classes, type: "button", ...rest, children: content });
51
+ }
52
+ );
53
+ Button.displayName = "Button";
54
+
55
+ // src/ColorPicker/ColorPicker.tsx
56
+ import * as React2 from "react";
57
+ import { jsx as jsx2 } from "react/jsx-runtime";
58
+ var CHECK_ICON = /* @__PURE__ */ jsx2("svg", { width: "12", height: "10", viewBox: "0 0 12 10", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx2(
59
+ "path",
60
+ {
61
+ d: "M1 5.5L4.5 9L11 1",
62
+ stroke: "currentColor",
63
+ strokeWidth: "2",
64
+ strokeLinecap: "round",
65
+ strokeLinejoin: "round"
66
+ }
67
+ ) });
68
+ var DEFAULT_COLORS = [
69
+ "#E53935",
70
+ "#FF9800",
71
+ "#FDD835",
72
+ "#8BC34A",
73
+ "#4CAF50",
74
+ "#009688",
75
+ "#00BCD4",
76
+ "#2196F3",
77
+ "#7B1FA2",
78
+ "#E91E63"
79
+ ];
80
+ var ColorPicker = React2.forwardRef(
81
+ ({
82
+ value = null,
83
+ onChange,
84
+ colors = DEFAULT_COLORS,
85
+ disabled = false,
86
+ className = "",
87
+ "aria-label": ariaLabel = "\u0412\u044B\u0431\u043E\u0440 \u0446\u0432\u0435\u0442\u0430"
88
+ }, ref) => {
89
+ const [hovered, setHovered] = React2.useState(null);
90
+ return /* @__PURE__ */ jsx2(
91
+ "div",
92
+ {
93
+ ref,
94
+ className: `astrum-color-swatch-picker ${className}`.trim(),
95
+ role: "listbox",
96
+ "aria-label": ariaLabel,
97
+ "aria-disabled": disabled,
98
+ children: colors.map((color) => {
99
+ const isSelected = value != null && value.toLowerCase() === color.toLowerCase();
100
+ const isHovered = hovered === color && !disabled;
101
+ return /* @__PURE__ */ jsx2(
102
+ "button",
103
+ {
104
+ type: "button",
105
+ role: "option",
106
+ "aria-selected": isSelected,
107
+ "aria-label": color,
108
+ disabled,
109
+ className: "astrum-color-swatch-picker__swatch",
110
+ style: { ["--astrum-swatch-color"]: color },
111
+ "data-selected": isSelected || void 0,
112
+ "data-hovered": isHovered || void 0,
113
+ onClick: () => onChange?.(color),
114
+ onMouseEnter: () => setHovered(color),
115
+ onMouseLeave: () => setHovered(null),
116
+ children: /* @__PURE__ */ jsx2("span", { className: "astrum-color-swatch-picker__check", "aria-hidden": true, children: CHECK_ICON })
117
+ },
118
+ color
119
+ );
120
+ })
121
+ }
122
+ );
123
+ }
124
+ );
125
+ ColorPicker.displayName = "ColorPicker";
126
+
127
+ // src/Radio/Radio.tsx
128
+ import * as React3 from "react";
129
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
130
+ var Radio = React3.forwardRef(
131
+ ({ value, className = "", id: idProp, ...rest }, ref) => {
132
+ const id = React3.useId();
133
+ const inputId = idProp ?? id;
134
+ return /* @__PURE__ */ jsxs2(
135
+ "label",
136
+ {
137
+ htmlFor: inputId,
138
+ className: `astrum-radio ${className}`.trim(),
139
+ children: [
140
+ /* @__PURE__ */ jsx3(
141
+ "input",
142
+ {
143
+ ref,
144
+ type: "radio",
145
+ id: inputId,
146
+ value,
147
+ className: "astrum-radio__input",
148
+ ...rest
149
+ }
150
+ ),
151
+ /* @__PURE__ */ jsx3("span", { className: "astrum-radio__circle", "aria-hidden": true })
152
+ ]
153
+ }
154
+ );
155
+ }
156
+ );
157
+ Radio.displayName = "Radio";
158
+ var RadioGroup = React3.forwardRef(
159
+ ({ name, value, onChange, children, ...rest }, ref) => {
160
+ const handleChange = React3.useCallback(
161
+ (e) => {
162
+ onChange?.(e.target.value);
163
+ },
164
+ [onChange]
165
+ );
166
+ return /* @__PURE__ */ jsx3("fieldset", { ref, className: "astrum-radio-group", ...rest, children: React3.Children.map(children, (child) => {
167
+ if (React3.isValidElement(child) && child.type === Radio) {
168
+ return React3.cloneElement(child, {
169
+ name,
170
+ checked: value != null && child.props.value === value,
171
+ onChange: (e) => {
172
+ child.props.onChange?.(e);
173
+ handleChange(e);
174
+ }
175
+ });
176
+ }
177
+ return child;
178
+ }) });
179
+ }
180
+ );
181
+ RadioGroup.displayName = "RadioGroup";
182
+
183
+ // src/Checkbox/Checkbox.tsx
184
+ import * as React4 from "react";
185
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
186
+ var CHECK_ICON2 = /* @__PURE__ */ jsx4("svg", { width: "12", height: "10", viewBox: "0 0 12 10", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx4(
187
+ "path",
188
+ {
189
+ d: "M1 5.5L4.5 9L11 1",
190
+ stroke: "currentColor",
191
+ strokeWidth: "2",
192
+ strokeLinecap: "round",
193
+ strokeLinejoin: "round"
194
+ }
195
+ ) });
196
+ var MINUS_ICON = /* @__PURE__ */ jsx4("svg", { width: "10", height: "2", viewBox: "0 0 10 2", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx4("path", { d: "M1 1h8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) });
197
+ var Checkbox = React4.forwardRef(
198
+ ({
199
+ checked: checkedProp,
200
+ indeterminate = false,
201
+ size = "m",
202
+ disabled = false,
203
+ onChange,
204
+ className = "",
205
+ id: idProp,
206
+ ...rest
207
+ }, ref) => {
208
+ const { defaultChecked, ...restInput } = rest;
209
+ const isControlled = checkedProp !== void 0;
210
+ const checked = checkedProp ?? false;
211
+ const [internalChecked, setInternalChecked] = React4.useState(defaultChecked ?? false);
212
+ const isChecked = (isControlled ? checked : internalChecked) || indeterminate;
213
+ const id = React4.useId();
214
+ const inputId = idProp ?? id;
215
+ const inputRef = React4.useRef(null);
216
+ const setRef = React4.useCallback(
217
+ (el) => {
218
+ inputRef.current = el;
219
+ if (typeof ref === "function") ref(el);
220
+ else if (ref) ref.current = el;
221
+ },
222
+ [ref]
223
+ );
224
+ React4.useEffect(() => {
225
+ const el = inputRef.current;
226
+ if (el) el.indeterminate = indeterminate;
227
+ }, [indeterminate]);
228
+ const handleChange = React4.useCallback(
229
+ (e) => {
230
+ if (disabled) return;
231
+ if (!isControlled) setInternalChecked(e.target.checked);
232
+ onChange?.(e.target.checked);
233
+ },
234
+ [disabled, isControlled, onChange]
235
+ );
236
+ return /* @__PURE__ */ jsxs3(
237
+ "label",
238
+ {
239
+ htmlFor: inputId,
240
+ className: [
241
+ "astrum-checkbox",
242
+ size === "s" ? "astrum-checkbox--s" : "astrum-checkbox--m",
243
+ isChecked ? "astrum-checkbox--checked" : "",
244
+ indeterminate ? "astrum-checkbox--indeterminate" : "",
245
+ disabled ? "astrum-checkbox--disabled" : "",
246
+ className
247
+ ].filter(Boolean).join(" "),
248
+ children: [
249
+ /* @__PURE__ */ jsx4(
250
+ "input",
251
+ {
252
+ ref: setRef,
253
+ type: "checkbox",
254
+ id: inputId,
255
+ className: "astrum-checkbox__input",
256
+ ...isControlled ? { checked } : { defaultChecked },
257
+ disabled,
258
+ onChange: handleChange,
259
+ "aria-checked": indeterminate ? "mixed" : isControlled ? checked : internalChecked,
260
+ ...restInput
261
+ }
262
+ ),
263
+ /* @__PURE__ */ jsx4("span", { className: "astrum-checkbox__box", "aria-hidden": true, children: isChecked && /* @__PURE__ */ jsx4("span", { className: "astrum-checkbox__icon", "aria-hidden": true, children: indeterminate ? MINUS_ICON : CHECK_ICON2 }) })
264
+ ]
265
+ }
266
+ );
267
+ }
268
+ );
269
+ Checkbox.displayName = "Checkbox";
270
+
271
+ // src/Toggler/Toggler.tsx
272
+ import * as React5 from "react";
273
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
274
+ var Toggler = React5.forwardRef(
275
+ ({ checked: checkedProp, disabled = false, onChange, className = "" }, ref) => {
276
+ const [internalChecked, setInternalChecked] = React5.useState(false);
277
+ const isControlled = checkedProp !== void 0;
278
+ const checked = isControlled ? checkedProp : internalChecked;
279
+ const handleChange = React5.useCallback(
280
+ (e) => {
281
+ if (!disabled) {
282
+ if (!isControlled) {
283
+ setInternalChecked(e.target.checked);
284
+ }
285
+ onChange?.(e.target.checked);
286
+ }
287
+ },
288
+ [disabled, onChange, isControlled]
289
+ );
290
+ const classes = [
291
+ "astrum-toggler",
292
+ checked && "astrum-toggler--checked",
293
+ disabled && "astrum-toggler--disabled",
294
+ className
295
+ ].filter(Boolean).join(" ");
296
+ return /* @__PURE__ */ jsxs4("label", { className: classes, children: [
297
+ /* @__PURE__ */ jsx5(
298
+ "input",
299
+ {
300
+ ref,
301
+ type: "checkbox",
302
+ checked: isControlled ? checked : void 0,
303
+ onChange: handleChange,
304
+ disabled,
305
+ className: "astrum-toggler__input"
306
+ }
307
+ ),
308
+ /* @__PURE__ */ jsx5("span", { className: "astrum-toggler__track", children: /* @__PURE__ */ jsx5("span", { className: "astrum-toggler__thumb" }) })
309
+ ] });
310
+ }
311
+ );
312
+ Toggler.displayName = "Toggler";
313
+
314
+ // src/Input/Input.tsx
315
+ import * as React6 from "react";
316
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
317
+ var SearchIcon = () => /* @__PURE__ */ jsxs5("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
318
+ /* @__PURE__ */ jsx6("circle", { cx: "11.0586", cy: "11.0586", r: "7.06194", stroke: "#ABABAB", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }),
319
+ /* @__PURE__ */ jsx6("path", { d: "M20.0033 20.0034L16.0517 16.0518", stroke: "#ABABAB", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" })
320
+ ] });
321
+ var ClearIcon = () => /* @__PURE__ */ jsxs5("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
322
+ /* @__PURE__ */ jsx6("path", { d: "M6.00037 6.00024L18.0004 18.0002", stroke: "#ABABAB", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
323
+ /* @__PURE__ */ jsx6("path", { d: "M18.0004 6.00024L6.00037 18.0002", stroke: "#ABABAB", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
324
+ ] });
325
+ var EyeOpenIcon = () => /* @__PURE__ */ jsxs5("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
326
+ /* @__PURE__ */ jsx6("path", { d: "M3 11.5455C3 11.5455 6.27273 5 12 5C17.7273 5 21 11.5455 21 11.5455C21 11.5455 17.7273 18.0909 12 18.0909C6.27273 18.0909 3 11.5455 3 11.5455Z", stroke: "#ABABAB", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }),
327
+ /* @__PURE__ */ jsx6("path", { d: "M12 14C13.3556 14 14.4545 12.9011 14.4545 11.5455C14.4545 10.1898 13.3556 9.09091 12 9.09091C10.6444 9.09091 9.54545 10.1898 9.54545 11.5455C9.54545 12.9011 10.6444 14 12 14Z", stroke: "#ABABAB", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" })
328
+ ] });
329
+ var EyeClosedIcon = () => /* @__PURE__ */ jsx6("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx6("path", { d: "M16.86 16.86C15.4614 17.9261 13.7584 18.5167 12 18.5455C6.27273 18.5455 3 12 3 12C4.01773 10.1034 5.42929 8.44632 7.14 7.14M10.2818 5.65091C10.845 5.51908 11.4216 5.45319 12 5.45455C17.7273 5.45455 21 12 21 12C20.5033 12.9291 19.911 13.8039 19.2327 14.61M13.7345 13.7345C13.5098 13.9757 13.2388 14.1691 12.9378 14.3033C12.6367 14.4374 12.3116 14.5096 11.9821 14.5154C11.6525 14.5212 11.3251 14.4606 11.0195 14.3371C10.7139 14.2137 10.4362 14.0299 10.2031 13.7969C9.97007 13.5638 9.78632 13.2861 9.66287 12.9805C9.53942 12.6749 9.47879 12.3475 9.48461 12.0179C9.49042 11.6884 9.56256 11.3633 9.69672 11.0622C9.83087 10.7612 10.0243 10.4902 10.2655 10.2655M3 3L21 21", stroke: "#ABABAB", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }) });
330
+ var Input = React6.forwardRef(
331
+ ({
332
+ type = "text",
333
+ name,
334
+ required = false,
335
+ label,
336
+ placeholder,
337
+ error,
338
+ value,
339
+ onChange,
340
+ disabled,
341
+ size = "m",
342
+ className = "",
343
+ id: idProp,
344
+ defaultValue,
345
+ ...rest
346
+ }, ref) => {
347
+ const id = React6.useId();
348
+ const inputId = idProp ?? id;
349
+ const [isPasswordVisible, setIsPasswordVisible] = React6.useState(false);
350
+ const [internalValue, setInternalValue] = React6.useState(defaultValue ?? "");
351
+ const inputRef = React6.useRef(null);
352
+ const combinedRef = React6.useCallback(
353
+ (node) => {
354
+ inputRef.current = node;
355
+ if (typeof ref === "function") {
356
+ ref(node);
357
+ } else if (ref) {
358
+ ref.current = node;
359
+ }
360
+ },
361
+ [ref]
362
+ );
363
+ const wrapClasses = [
364
+ "astrum-input__wrap",
365
+ type === "search" && "astrum-input__wrap--search",
366
+ type === "password" && "astrum-input__wrap--password"
367
+ ].filter(Boolean).join(" ");
368
+ const inputType = type === "password" && isPasswordVisible ? "text" : type;
369
+ const sizeClass = size === "s" ? "astrum-input--s" : "astrum-input--m";
370
+ const isControlled = value !== void 0;
371
+ const currentValue = isControlled ? value : internalValue;
372
+ const hasValue = currentValue != null && currentValue !== "";
373
+ const handleChange = React6.useCallback(
374
+ (e) => {
375
+ if (!isControlled) {
376
+ setInternalValue(e.target.value);
377
+ }
378
+ onChange?.(e);
379
+ },
380
+ [onChange, isControlled]
381
+ );
382
+ const handleClear = React6.useCallback(
383
+ (e) => {
384
+ e.stopPropagation();
385
+ if (inputRef.current) {
386
+ if (isControlled && onChange) {
387
+ const syntheticEvent = {
388
+ ...e,
389
+ target: inputRef.current,
390
+ currentTarget: inputRef.current
391
+ };
392
+ Object.defineProperty(syntheticEvent.target, "value", {
393
+ writable: true,
394
+ value: ""
395
+ });
396
+ onChange(syntheticEvent);
397
+ } else {
398
+ setInternalValue("");
399
+ inputRef.current.value = "";
400
+ if (onChange) {
401
+ const syntheticEvent = {
402
+ ...e,
403
+ target: inputRef.current,
404
+ currentTarget: inputRef.current
405
+ };
406
+ Object.defineProperty(syntheticEvent.target, "value", {
407
+ writable: true,
408
+ value: ""
409
+ });
410
+ onChange(syntheticEvent);
411
+ }
412
+ }
413
+ inputRef.current.focus();
414
+ }
415
+ },
416
+ [onChange, isControlled]
417
+ );
418
+ return /* @__PURE__ */ jsxs5(
419
+ "div",
420
+ {
421
+ className: `astrum-input ${sizeClass} ${error ? "astrum-input--error" : ""} ${className}`.trim(),
422
+ children: [
423
+ label != null && /* @__PURE__ */ jsx6("label", { htmlFor: inputId, className: "astrum-input__label", children: label }),
424
+ /* @__PURE__ */ jsxs5("div", { className: wrapClasses, children: [
425
+ required && /* @__PURE__ */ jsx6("span", { className: "astrum-input__required-icon", "aria-hidden": true, children: /* @__PURE__ */ jsx6("svg", { width: "7", height: "6", viewBox: "0 0 7 6", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx6("path", { d: "M2.21831 3.52817L0 3.57042V2.47183L2.21831 2.53521L1.03521 0.59155L2.07042 0L3.19014 1.90141L4.28873 0L5.28169 0.59155L4.07746 2.53521L6.25352 2.47183V3.57042L4.09859 3.52817L5.26056 5.42958L4.26761 6L3.14789 4.07747L2.02817 6L1.01408 5.40845L2.21831 3.52817Z", fill: "#ABABAB" }) }) }),
426
+ /* @__PURE__ */ jsx6(
427
+ "input",
428
+ {
429
+ ref: combinedRef,
430
+ id: inputId,
431
+ type: inputType,
432
+ name,
433
+ placeholder,
434
+ value: isControlled ? value : void 0,
435
+ defaultValue: isControlled ? void 0 : defaultValue,
436
+ onChange: handleChange,
437
+ required,
438
+ disabled,
439
+ className: `astrum-input__field ${error ? "astrum-input__field--invalid" : ""}`.trim(),
440
+ "aria-invalid": !!error,
441
+ "aria-required": required,
442
+ "aria-describedby": error ? `${inputId}-error` : void 0,
443
+ ...rest
444
+ }
445
+ ),
446
+ type === "search" && /* @__PURE__ */ jsx6(Fragment2, { children: hasValue ? /* @__PURE__ */ jsx6(
447
+ "button",
448
+ {
449
+ type: "button",
450
+ className: "astrum-input__clear-icon",
451
+ onClick: handleClear,
452
+ tabIndex: -1,
453
+ "aria-label": "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
454
+ children: /* @__PURE__ */ jsx6(ClearIcon, {})
455
+ }
456
+ ) : /* @__PURE__ */ jsx6("span", { className: "astrum-input__search-icon", "aria-hidden": true, children: /* @__PURE__ */ jsx6(SearchIcon, {}) }) }),
457
+ type === "password" && /* @__PURE__ */ jsx6(
458
+ "button",
459
+ {
460
+ type: "button",
461
+ className: "astrum-input__password-toggle",
462
+ onClick: () => setIsPasswordVisible((prev) => !prev),
463
+ tabIndex: -1,
464
+ "aria-label": isPasswordVisible ? "\u0421\u043A\u0440\u044B\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C" : "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C",
465
+ children: isPasswordVisible ? /* @__PURE__ */ jsx6(EyeOpenIcon, {}) : /* @__PURE__ */ jsx6(EyeClosedIcon, {})
466
+ }
467
+ )
468
+ ] }),
469
+ error != null && /* @__PURE__ */ jsx6("span", { id: `${inputId}-error`, className: "astrum-input__error", role: "alert", children: error })
470
+ ]
471
+ }
472
+ );
473
+ }
474
+ );
475
+ Input.displayName = "Input";
476
+
477
+ // src/InputCode/InputCode.tsx
478
+ import * as React7 from "react";
479
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
480
+ var LENGTH = 6;
481
+ function normalizeValue(s) {
482
+ return s.replace(/\D/g, "").slice(0, LENGTH);
483
+ }
484
+ var InputCode = React7.forwardRef(
485
+ ({
486
+ value: valueProp,
487
+ defaultValue = "",
488
+ onChange,
489
+ onComplete,
490
+ error,
491
+ required,
492
+ disabled = false,
493
+ id: idProp,
494
+ className = ""
495
+ }, ref) => {
496
+ const id = React7.useId();
497
+ const rootId = idProp ?? id;
498
+ const [internalValue, setInternalValue] = React7.useState(
499
+ () => normalizeValue(defaultValue)
500
+ );
501
+ const value = valueProp !== void 0 ? normalizeValue(valueProp) : internalValue;
502
+ const digits = value.split("");
503
+ while (digits.length < LENGTH) digits.push("");
504
+ const inputRefs = React7.useRef([]);
505
+ for (let i = 0; i < LENGTH; i++) {
506
+ if (!inputRefs.current[i]) {
507
+ inputRefs.current[i] = null;
508
+ }
509
+ }
510
+ const setValue = React7.useCallback(
511
+ (next) => {
512
+ const normalized = normalizeValue(next);
513
+ if (valueProp === void 0) setInternalValue(normalized);
514
+ onChange?.(normalized);
515
+ if (normalized.length === LENGTH) onComplete?.(normalized);
516
+ },
517
+ [valueProp, onChange, onComplete]
518
+ );
519
+ React7.useEffect(() => {
520
+ if (value.length === LENGTH && onComplete) {
521
+ onComplete(value);
522
+ }
523
+ }, [value, onComplete]);
524
+ React7.useEffect(() => {
525
+ inputRefs.current.forEach((ref2, index) => {
526
+ if (ref2) {
527
+ ref2.value = digits[index] || "";
528
+ }
529
+ });
530
+ }, [value, digits]);
531
+ const handleInput = React7.useCallback(
532
+ (e, index) => {
533
+ const input = e.target;
534
+ const previousInput = inputRefs.current[index - 1];
535
+ const nextInput = inputRefs.current[index + 1];
536
+ const newCode = [...digits];
537
+ const char = normalizeValue(input.value);
538
+ if (char) {
539
+ newCode[index] = char;
540
+ setValue(newCode.join(""));
541
+ input.select();
542
+ if (nextInput) {
543
+ nextInput.focus();
544
+ nextInput.select();
545
+ }
546
+ } else {
547
+ newCode[index] = "";
548
+ setValue(newCode.join(""));
549
+ if (previousInput) {
550
+ previousInput.focus();
551
+ previousInput.select();
552
+ }
553
+ }
554
+ },
555
+ [digits, setValue]
556
+ );
557
+ const handleFocus = React7.useCallback(
558
+ (e) => {
559
+ e.target.select();
560
+ },
561
+ []
562
+ );
563
+ const handleKeyDown = React7.useCallback(
564
+ (e, index) => {
565
+ const input = e.target;
566
+ const previousInput = inputRefs.current[index - 1];
567
+ if ((e.key === "Backspace" || e.key === "Delete") && !input.value && index > 0) {
568
+ e.preventDefault();
569
+ const newCode = [...digits];
570
+ newCode[index - 1] = "";
571
+ setValue(newCode.join(""));
572
+ if (previousInput) {
573
+ previousInput.focus();
574
+ previousInput.select();
575
+ }
576
+ }
577
+ },
578
+ [digits, setValue]
579
+ );
580
+ const handlePaste = React7.useCallback(
581
+ (e) => {
582
+ e.preventDefault();
583
+ const pastedCode = normalizeValue(e.clipboardData.getData("text"));
584
+ if (pastedCode.length === LENGTH) {
585
+ setValue(pastedCode);
586
+ inputRefs.current.forEach((inputRef, index) => {
587
+ if (inputRef) {
588
+ inputRef.value = pastedCode[index] || "";
589
+ }
590
+ });
591
+ const lastInput = inputRefs.current[LENGTH - 1];
592
+ if (lastInput) {
593
+ lastInput.focus();
594
+ lastInput.select();
595
+ }
596
+ } else if (pastedCode.length > 0) {
597
+ const activeIndex = inputRefs.current.findIndex(
598
+ (ref2) => ref2 === document.activeElement
599
+ );
600
+ if (activeIndex >= 0) {
601
+ const newCode = [...digits];
602
+ for (let i = 0; i < pastedCode.length && activeIndex + i < LENGTH; i++) {
603
+ newCode[activeIndex + i] = pastedCode[i];
604
+ }
605
+ setValue(newCode.join(""));
606
+ const nextIndex = Math.min(activeIndex + pastedCode.length, LENGTH - 1);
607
+ const nextInput = inputRefs.current[nextIndex];
608
+ if (nextInput) {
609
+ nextInput.focus();
610
+ nextInput.select();
611
+ }
612
+ }
613
+ }
614
+ },
615
+ [digits, setValue]
616
+ );
617
+ return /* @__PURE__ */ jsxs6(
618
+ "div",
619
+ {
620
+ ref,
621
+ id: rootId,
622
+ className: `astrum-input-code ${error ? "astrum-input-code--error" : ""} ${className}`.trim(),
623
+ children: [
624
+ /* @__PURE__ */ jsx7("div", { className: "astrum-input-code__wrap", children: digits.map((digit, index) => /* @__PURE__ */ jsx7(
625
+ "input",
626
+ {
627
+ ref: (el) => {
628
+ inputRefs.current[index] = el;
629
+ },
630
+ id: index === 0 ? `${rootId}-0` : void 0,
631
+ type: "text",
632
+ inputMode: "numeric",
633
+ autoComplete: index === 0 ? "one-time-code" : "off",
634
+ maxLength: 1,
635
+ className: `astrum-input-code__cell ${index === 3 ? "astrum-input-code__cell--spaced" : ""}`.trim(),
636
+ value: digit,
637
+ onChange: (e) => handleInput(e, index),
638
+ onFocus: handleFocus,
639
+ onKeyDown: (e) => handleKeyDown(e, index),
640
+ onPaste: handlePaste,
641
+ disabled,
642
+ "aria-invalid": !!error,
643
+ "aria-required": required,
644
+ "aria-describedby": error ? `${rootId}-error` : void 0
645
+ },
646
+ index
647
+ )) }),
648
+ error != null && /* @__PURE__ */ jsx7("div", { className: "astrum-input-code__footer", children: /* @__PURE__ */ jsx7(
649
+ "span",
650
+ {
651
+ id: `${rootId}-error`,
652
+ className: "astrum-input-code__error",
653
+ role: "alert",
654
+ children: error
655
+ }
656
+ ) })
657
+ ]
658
+ }
659
+ );
660
+ }
661
+ );
662
+ InputCode.displayName = "InputCode";
663
+
664
+ // src/Select/Select.tsx
665
+ import * as React8 from "react";
666
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
667
+ var ChevronDownIcon = () => /* @__PURE__ */ jsx8("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx8(
668
+ "path",
669
+ {
670
+ d: "M5 7.5l5 5 5-5",
671
+ stroke: "currentColor",
672
+ strokeWidth: "1.5",
673
+ strokeLinecap: "round",
674
+ strokeLinejoin: "round"
675
+ }
676
+ ) });
677
+ var Select = React8.forwardRef(
678
+ ({
679
+ label,
680
+ error,
681
+ required,
682
+ options,
683
+ placeholder,
684
+ size = "m",
685
+ className = "",
686
+ id: idProp,
687
+ value,
688
+ defaultValue,
689
+ onChange,
690
+ disabled,
691
+ ...rest
692
+ }, ref) => {
693
+ const id = React8.useId();
694
+ const selectId = idProp ?? id;
695
+ const [isOpen, setIsOpen] = React8.useState(false);
696
+ const selectRef = React8.useRef(null);
697
+ const dropdownRef = React8.useRef(null);
698
+ const containerRef = React8.useRef(null);
699
+ const setRef = React8.useCallback(
700
+ (el) => {
701
+ selectRef.current = el;
702
+ if (typeof ref === "function") ref(el);
703
+ else if (ref) ref.current = el;
704
+ },
705
+ [ref]
706
+ );
707
+ const currentValue = value !== void 0 ? value : defaultValue ?? "";
708
+ const selectedOption = currentValue ? options.find((opt) => opt.value === currentValue) : null;
709
+ const displayValue = selectedOption ? selectedOption.label : placeholder ?? "";
710
+ React8.useEffect(() => {
711
+ const handleClickOutside = (e) => {
712
+ if (containerRef.current && !containerRef.current.contains(e.target) && dropdownRef.current && !dropdownRef.current.contains(e.target)) {
713
+ setIsOpen(false);
714
+ }
715
+ };
716
+ if (isOpen) {
717
+ document.addEventListener("mousedown", handleClickOutside);
718
+ return () => document.removeEventListener("mousedown", handleClickOutside);
719
+ }
720
+ }, [isOpen]);
721
+ const handleOptionClick = (optionValue) => {
722
+ if (selectRef.current) {
723
+ const nativeEvent = new Event("change", { bubbles: true });
724
+ Object.defineProperty(nativeEvent, "target", {
725
+ writable: false,
726
+ value: selectRef.current
727
+ });
728
+ selectRef.current.value = optionValue;
729
+ selectRef.current.dispatchEvent(nativeEvent);
730
+ const reactEvent = {
731
+ ...nativeEvent,
732
+ target: selectRef.current,
733
+ currentTarget: selectRef.current
734
+ };
735
+ onChange?.(reactEvent);
736
+ }
737
+ setIsOpen(false);
738
+ };
739
+ const handleKeyDown = (e) => {
740
+ if (e.key === "Enter" || e.key === " ") {
741
+ e.preventDefault();
742
+ setIsOpen(!isOpen);
743
+ } else if (e.key === "Escape") {
744
+ setIsOpen(false);
745
+ } else if (e.key === "ArrowDown" && !isOpen) {
746
+ e.preventDefault();
747
+ setIsOpen(true);
748
+ }
749
+ };
750
+ return /* @__PURE__ */ jsxs7(Fragment3, { children: [
751
+ /* @__PURE__ */ jsxs7(
752
+ "div",
753
+ {
754
+ ref: containerRef,
755
+ className: `astrum-select ${size === "s" ? "astrum-select--s" : size === "l" ? "astrum-select--l" : "astrum-select--m"} ${error ? "astrum-select--error" : ""} ${isOpen ? "astrum-select--open" : ""} ${className}`.trim(),
756
+ children: [
757
+ label != null && /* @__PURE__ */ jsxs7("label", { htmlFor: selectId, className: "astrum-select__label", children: [
758
+ label,
759
+ required && /* @__PURE__ */ jsx8("span", { className: "astrum-select__required", "aria-hidden": true, children: "*" })
760
+ ] }),
761
+ /* @__PURE__ */ jsxs7("div", { className: "astrum-select__wrap", children: [
762
+ /* @__PURE__ */ jsxs7(
763
+ "select",
764
+ {
765
+ ref: setRef,
766
+ id: selectId,
767
+ className: "astrum-select__field",
768
+ value: value !== void 0 ? value : void 0,
769
+ defaultValue: value === void 0 ? defaultValue : void 0,
770
+ onChange: (e) => {
771
+ onChange?.(e);
772
+ setIsOpen(false);
773
+ },
774
+ onMouseDown: (e) => {
775
+ e.preventDefault();
776
+ if (!disabled) setIsOpen(!isOpen);
777
+ },
778
+ onClick: (e) => {
779
+ e.preventDefault();
780
+ if (!disabled) setIsOpen(!isOpen);
781
+ },
782
+ disabled,
783
+ "aria-invalid": !!error,
784
+ "aria-required": required,
785
+ "aria-describedby": error ? `${selectId}-error` : void 0,
786
+ "aria-expanded": isOpen,
787
+ ...rest,
788
+ children: [
789
+ placeholder && /* @__PURE__ */ jsx8("option", { value: "", disabled: true, hidden: true, children: placeholder }),
790
+ options.map((option) => /* @__PURE__ */ jsx8("option", { value: option.value, disabled: option.disabled, children: typeof option.label === "string" ? option.label : option.value }, option.value))
791
+ ]
792
+ }
793
+ ),
794
+ /* @__PURE__ */ jsxs7(
795
+ "button",
796
+ {
797
+ type: "button",
798
+ className: "astrum-select__trigger",
799
+ onClick: () => !disabled && setIsOpen(!isOpen),
800
+ onKeyDown: handleKeyDown,
801
+ disabled,
802
+ "aria-label": "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A",
803
+ "aria-haspopup": "listbox",
804
+ "aria-expanded": isOpen,
805
+ children: [
806
+ /* @__PURE__ */ jsx8("span", { className: `astrum-select__value ${!selectedOption && placeholder ? "astrum-select__value--placeholder" : ""}`, children: displayValue }),
807
+ /* @__PURE__ */ jsx8("span", { className: `astrum-select__chevron ${isOpen ? "astrum-select__chevron--open" : ""}`, children: /* @__PURE__ */ jsx8(ChevronDownIcon, {}) })
808
+ ]
809
+ }
810
+ )
811
+ ] }),
812
+ error != null && /* @__PURE__ */ jsx8("div", { className: "astrum-select__footer", children: /* @__PURE__ */ jsx8("span", { id: `${selectId}-error`, className: "astrum-select__error", role: "alert", children: error }) })
813
+ ]
814
+ }
815
+ ),
816
+ isOpen && /* @__PURE__ */ jsx8("div", { ref: dropdownRef, className: "astrum-select__dropdown", role: "listbox", children: options.map((option) => /* @__PURE__ */ jsx8(
817
+ "button",
818
+ {
819
+ type: "button",
820
+ role: "option",
821
+ "aria-selected": option.value === currentValue,
822
+ className: `astrum-select__option ${option.value === currentValue ? "astrum-select__option--selected" : ""} ${option.disabled ? "astrum-select__option--disabled" : ""}`,
823
+ onClick: () => !option.disabled && handleOptionClick(option.value),
824
+ disabled: option.disabled,
825
+ children: option.label
826
+ },
827
+ option.value
828
+ )) })
829
+ ] });
830
+ }
831
+ );
832
+ Select.displayName = "Select";
833
+
834
+ // src/Chips/Chips.tsx
835
+ import * as React9 from "react";
836
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
837
+ var CloseIcon = () => /* @__PURE__ */ jsx9("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx9(
838
+ "path",
839
+ {
840
+ d: "M3 3l6 6M9 3l-6 6",
841
+ stroke: "currentColor",
842
+ strokeWidth: "1.5",
843
+ strokeLinecap: "round"
844
+ }
845
+ ) });
846
+ var Chips = React9.forwardRef(
847
+ ({
848
+ children,
849
+ size = "s",
850
+ onRemove,
851
+ className = "",
852
+ onClick,
853
+ ...rest
854
+ }, ref) => {
855
+ const handleRemove = React9.useCallback(
856
+ (e) => {
857
+ e.stopPropagation();
858
+ onRemove?.();
859
+ },
860
+ [onRemove]
861
+ );
862
+ const handleClick = React9.useCallback(
863
+ (e) => {
864
+ if (onRemove && e.target === e.currentTarget) {
865
+ return;
866
+ }
867
+ onClick?.(e);
868
+ },
869
+ [onClick, onRemove]
870
+ );
871
+ return /* @__PURE__ */ jsxs8(
872
+ "button",
873
+ {
874
+ ref,
875
+ type: "button",
876
+ className: `astrum-chips ${size === "s" ? "astrum-chips--s" : "astrum-chips--m"} ${className}`.trim(),
877
+ onClick: handleClick,
878
+ ...rest,
879
+ children: [
880
+ /* @__PURE__ */ jsx9("span", { className: "astrum-chips__text", children }),
881
+ /* @__PURE__ */ jsx9(
882
+ "button",
883
+ {
884
+ type: "button",
885
+ className: "astrum-chips__remove",
886
+ onClick: handleRemove,
887
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
888
+ children: /* @__PURE__ */ jsx9(CloseIcon, {})
889
+ }
890
+ )
891
+ ]
892
+ }
893
+ );
894
+ }
895
+ );
896
+ Chips.displayName = "Chips";
897
+
898
+ // src/FileUpload/FileUpload.tsx
899
+ import * as React10 from "react";
900
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
901
+ var UploadIcon = () => /* @__PURE__ */ jsx10("svg", { width: "48", height: "48", viewBox: "0 0 48 48", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx10(
902
+ "path",
903
+ {
904
+ d: "M24 8v24m0 0l-8-8m8 8l8-8M8 32h32",
905
+ stroke: "currentColor",
906
+ strokeWidth: "2",
907
+ strokeLinecap: "round",
908
+ strokeLinejoin: "round"
909
+ }
910
+ ) });
911
+ var FileIcon = () => /* @__PURE__ */ jsxs9("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
912
+ /* @__PURE__ */ jsx10(
913
+ "path",
914
+ {
915
+ d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z",
916
+ stroke: "currentColor",
917
+ strokeWidth: "1.5",
918
+ strokeLinecap: "round",
919
+ strokeLinejoin: "round"
920
+ }
921
+ ),
922
+ /* @__PURE__ */ jsx10("path", { d: "M14 2v6h6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
923
+ ] });
924
+ var CloseIcon2 = () => /* @__PURE__ */ jsx10("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx10(
925
+ "path",
926
+ {
927
+ d: "M4 4l8 8M12 4l-8 8",
928
+ stroke: "currentColor",
929
+ strokeWidth: "1.5",
930
+ strokeLinecap: "round"
931
+ }
932
+ ) });
933
+ var FileUpload = React10.forwardRef(
934
+ ({
935
+ accept,
936
+ multiple = false,
937
+ disabled = false,
938
+ size = "large",
939
+ label,
940
+ description,
941
+ buttonText = "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B\u044B",
942
+ onChange,
943
+ className = ""
944
+ }, ref) => {
945
+ const inputRef = React10.useRef(null);
946
+ const [isDragging, setIsDragging] = React10.useState(false);
947
+ const [files, setFiles] = React10.useState(null);
948
+ const setRef = React10.useCallback(
949
+ (el) => {
950
+ inputRef.current = el;
951
+ if (typeof ref === "function") ref(el);
952
+ else if (ref) ref.current = el;
953
+ },
954
+ [ref]
955
+ );
956
+ const handleDragEnter = React10.useCallback((e) => {
957
+ e.preventDefault();
958
+ e.stopPropagation();
959
+ if (!disabled) setIsDragging(true);
960
+ }, [disabled]);
961
+ const handleDragLeave = React10.useCallback((e) => {
962
+ e.preventDefault();
963
+ e.stopPropagation();
964
+ setIsDragging(false);
965
+ }, []);
966
+ const handleDragOver = React10.useCallback((e) => {
967
+ e.preventDefault();
968
+ e.stopPropagation();
969
+ }, []);
970
+ const handleDrop = React10.useCallback(
971
+ (e) => {
972
+ e.preventDefault();
973
+ e.stopPropagation();
974
+ setIsDragging(false);
975
+ if (disabled) return;
976
+ const droppedFiles = e.dataTransfer.files;
977
+ if (droppedFiles.length > 0) {
978
+ setFiles(droppedFiles);
979
+ onChange?.(droppedFiles);
980
+ }
981
+ },
982
+ [disabled, onChange]
983
+ );
984
+ const handleFileChange = React10.useCallback(
985
+ (e) => {
986
+ const selectedFiles = e.target.files;
987
+ if (selectedFiles && selectedFiles.length > 0) {
988
+ setFiles(selectedFiles);
989
+ onChange?.(selectedFiles);
990
+ }
991
+ },
992
+ [onChange]
993
+ );
994
+ const handleButtonClick = React10.useCallback(() => {
995
+ if (!disabled && inputRef.current) {
996
+ inputRef.current.click();
997
+ }
998
+ }, [disabled]);
999
+ const defaultLabel = label ?? (accept?.includes("pdf") ? "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 PDF-\u0444\u0430\u0439\u043B\u044B" : "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B\u044B");
1000
+ const defaultDescription = description ?? (size === "large" ? "\u041F\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0444\u0430\u0439\u043B\u044B \u0441\u044E\u0434\u0430 \u0438\u043B\u0438 \u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0438\u0445, \u0449\u0435\u043B\u043A\u043D\u0443\u0432 \u043C\u044B\u0448\u044C\u044E." : "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B \u0438\u043B\u0438 \u043F\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0441\u044E\u0434\u0430");
1001
+ return /* @__PURE__ */ jsxs9(
1002
+ "div",
1003
+ {
1004
+ className: `astrum-file-upload ${size === "compact" ? "astrum-file-upload--compact" : "astrum-file-upload--large"} ${isDragging ? "astrum-file-upload--dragging" : ""} ${disabled ? "astrum-file-upload--disabled" : ""} ${className}`.trim(),
1005
+ onDragEnter: handleDragEnter,
1006
+ onDragLeave: handleDragLeave,
1007
+ onDragOver: handleDragOver,
1008
+ onDrop: handleDrop,
1009
+ children: [
1010
+ /* @__PURE__ */ jsx10(
1011
+ "input",
1012
+ {
1013
+ ref: setRef,
1014
+ type: "file",
1015
+ accept,
1016
+ multiple,
1017
+ disabled,
1018
+ onChange: handleFileChange,
1019
+ className: "astrum-file-upload__input",
1020
+ "aria-label": defaultLabel
1021
+ }
1022
+ ),
1023
+ size === "large" ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
1024
+ /* @__PURE__ */ jsx10("div", { className: "astrum-file-upload__icon", children: /* @__PURE__ */ jsx10(UploadIcon, {}) }),
1025
+ /* @__PURE__ */ jsx10("div", { className: "astrum-file-upload__label", children: defaultLabel }),
1026
+ /* @__PURE__ */ jsx10("div", { className: "astrum-file-upload__description", children: defaultDescription }),
1027
+ /* @__PURE__ */ jsx10(Button, { variant: "primary", size: "m", onClick: handleButtonClick, disabled, children: buttonText })
1028
+ ] }) : /* @__PURE__ */ jsx10("div", { className: "astrum-file-upload__compact-content", children: /* @__PURE__ */ jsxs9("span", { className: "astrum-file-upload__compact-text", children: [
1029
+ /* @__PURE__ */ jsx10(
1030
+ "button",
1031
+ {
1032
+ type: "button",
1033
+ className: "astrum-file-upload__compact-link",
1034
+ onClick: handleButtonClick,
1035
+ disabled,
1036
+ children: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B"
1037
+ }
1038
+ ),
1039
+ " ",
1040
+ "\u0438\u043B\u0438 \u043F\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0441\u044E\u0434\u0430"
1041
+ ] }) })
1042
+ ]
1043
+ }
1044
+ );
1045
+ }
1046
+ );
1047
+ FileUpload.displayName = "FileUpload";
1048
+ var FileItem = React10.forwardRef(
1049
+ ({ name, size, icon, onRemove, className = "" }, ref) => {
1050
+ const formatSize = React10.useCallback((sizeValue) => {
1051
+ if (!sizeValue) return "";
1052
+ if (typeof sizeValue === "string") return sizeValue;
1053
+ if (sizeValue < 1024) return `${sizeValue} B`;
1054
+ if (sizeValue < 1024 * 1024) return `${(sizeValue / 1024).toFixed(0)} KB`;
1055
+ return `${(sizeValue / (1024 * 1024)).toFixed(1)} MB`;
1056
+ }, []);
1057
+ return /* @__PURE__ */ jsxs9("div", { ref, className: `astrum-file-item ${className}`.trim(), children: [
1058
+ /* @__PURE__ */ jsx10("div", { className: "astrum-file-item__icon", children: icon ?? /* @__PURE__ */ jsx10(FileIcon, {}) }),
1059
+ /* @__PURE__ */ jsxs9("div", { className: "astrum-file-item__content", children: [
1060
+ /* @__PURE__ */ jsx10("div", { className: "astrum-file-item__name", children: name }),
1061
+ size != null && /* @__PURE__ */ jsx10("div", { className: "astrum-file-item__size", children: formatSize(size) })
1062
+ ] }),
1063
+ onRemove != null && /* @__PURE__ */ jsx10(
1064
+ "button",
1065
+ {
1066
+ type: "button",
1067
+ className: "astrum-file-item__remove",
1068
+ onClick: onRemove,
1069
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0444\u0430\u0439\u043B",
1070
+ children: /* @__PURE__ */ jsx10(CloseIcon2, {})
1071
+ }
1072
+ )
1073
+ ] });
1074
+ }
1075
+ );
1076
+ FileItem.displayName = "FileItem";
1077
+
1078
+ // src/Avatar/Avatar.tsx
1079
+ import * as React11 from "react";
1080
+ import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1081
+ function cn(...args) {
1082
+ return args.flatMap(
1083
+ (x) => typeof x === "object" && x !== null ? Object.entries(x).filter(([, v]) => v).map(([k]) => k) : x
1084
+ ).filter(Boolean).join(" ");
1085
+ }
1086
+ var UserIcon = () => /* @__PURE__ */ jsx11("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx11("path", { d: "M16 4C13.6266 4 11.3066 4.70379 9.33316 6.02236C7.35977 7.34094 5.8217 9.21508 4.91345 11.4078C4.0052 13.6005 3.76756 16.0133 4.23058 18.3411C4.6936 20.6689 5.83649 22.807 7.51472 24.4853C9.19295 26.1635 11.3311 27.3064 13.6589 27.7694C15.9867 28.2324 18.3995 27.9948 20.5922 27.0865C22.7849 26.1783 24.6591 24.6402 25.9776 22.6668C27.2962 20.6934 28 18.3734 28 16C27.9988 12.8178 26.7342 9.76618 24.484 7.51599C22.2338 5.2658 19.1822 4.00115 16 4ZM16 8.8C16.5807 8.8 17.1483 8.97219 17.6312 9.2948C18.114 9.61742 18.4903 10.076 18.7125 10.6124C18.9347 11.1489 18.9929 11.7393 18.8796 12.3088C18.7663 12.8783 18.4867 13.4015 18.0761 13.8121C17.6655 14.2227 17.1423 14.5023 16.5728 14.6156C16.0033 14.7289 15.4129 14.6707 14.8764 14.4485C14.34 14.2263 13.8814 13.85 13.5588 13.3672C13.2362 12.8843 13.064 12.3167 13.064 11.736C13.0645 10.9575 13.374 10.211 13.9245 9.66049C14.475 9.11 15.2215 8.80051 16 8.8ZM21.224 21.2C21.2242 21.7291 21.0147 22.2368 20.6413 22.6117C20.2679 22.9866 19.7611 23.1981 19.232 23.2H12.768C12.2389 23.1981 11.7321 22.9866 11.3587 22.6117C10.9853 22.2368 10.7758 21.7291 10.776 21.2V19.864C10.7768 18.8182 11.1925 17.8155 11.932 17.076C12.6715 16.3365 13.6742 15.9208 14.72 15.92H17.28C18.3258 15.9208 19.3285 16.3365 20.068 17.076C20.8075 17.8155 21.2232 18.8182 21.224 19.864V21.2Z", fill: "#ABABAB" }) });
1087
+ var EditIcon = () => /* @__PURE__ */ jsxs10("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1088
+ /* @__PURE__ */ jsx11("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M5.293 15.619L15.619 5.29299C16.009 4.90299 16.642 4.90299 17.032 5.29299L18.708 6.96899C19.098 7.35899 19.098 7.99199 18.708 8.38199L8.381 18.707C8.194 18.895 7.94 19 7.675 19H5V16.325C5 16.06 5.105 15.806 5.293 15.619Z", stroke: "white", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }),
1089
+ /* @__PURE__ */ jsx11("path", { d: "M13.75 7.16016L16.84 10.2502", stroke: "white", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" })
1090
+ ] });
1091
+ var CrossIcon = () => /* @__PURE__ */ jsx11("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx11(
1092
+ "path",
1093
+ {
1094
+ d: "M4 4l8 8M12 4l-8 8",
1095
+ stroke: "currentColor",
1096
+ strokeWidth: "1.5",
1097
+ strokeLinecap: "round"
1098
+ }
1099
+ ) });
1100
+ var Avatar = React11.forwardRef(
1101
+ ({
1102
+ src,
1103
+ alt = "Avatar",
1104
+ size = 56,
1105
+ onUpload,
1106
+ onEdit,
1107
+ onRemove,
1108
+ className
1109
+ }, ref) => {
1110
+ const [isHovered, setIsHovered] = React11.useState(false);
1111
+ const fileInputRef = React11.useRef(null);
1112
+ const handleFileChange = React11.useCallback(
1113
+ (e) => {
1114
+ const file = e.target.files?.[0];
1115
+ if (file && onUpload) {
1116
+ onUpload(file);
1117
+ }
1118
+ if (fileInputRef.current) {
1119
+ fileInputRef.current.value = "";
1120
+ }
1121
+ },
1122
+ [onUpload]
1123
+ );
1124
+ const handleClick = React11.useCallback(() => {
1125
+ if (src) {
1126
+ if (onEdit) {
1127
+ onEdit();
1128
+ } else if (fileInputRef.current) {
1129
+ fileInputRef.current.click();
1130
+ }
1131
+ } else {
1132
+ if (fileInputRef.current) {
1133
+ fileInputRef.current.click();
1134
+ }
1135
+ }
1136
+ }, [src, onEdit]);
1137
+ const handleRemove = React11.useCallback(
1138
+ (e) => {
1139
+ e.stopPropagation();
1140
+ if (onRemove) {
1141
+ onRemove();
1142
+ }
1143
+ },
1144
+ [onRemove]
1145
+ );
1146
+ const hasImage = Boolean(src);
1147
+ return /* @__PURE__ */ jsxs10(
1148
+ "div",
1149
+ {
1150
+ ref,
1151
+ className: cn(
1152
+ "astrum-avatar",
1153
+ {
1154
+ "astrum-avatar--has-image": hasImage,
1155
+ "astrum-avatar--hovered": isHovered
1156
+ },
1157
+ className
1158
+ ),
1159
+ style: { width: size, height: size },
1160
+ onMouseEnter: () => setIsHovered(true),
1161
+ onMouseLeave: () => setIsHovered(false),
1162
+ onClick: handleClick,
1163
+ children: [
1164
+ onUpload && /* @__PURE__ */ jsx11(
1165
+ "input",
1166
+ {
1167
+ ref: fileInputRef,
1168
+ type: "file",
1169
+ accept: "image/*",
1170
+ onChange: handleFileChange,
1171
+ className: "astrum-avatar__input"
1172
+ }
1173
+ ),
1174
+ hasImage ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
1175
+ /* @__PURE__ */ jsxs10("div", { className: "astrum-avatar__body", children: [
1176
+ /* @__PURE__ */ jsx11("img", { src, alt, className: "astrum-avatar__image" }),
1177
+ /* @__PURE__ */ jsx11("div", { className: "astrum-avatar__overlay", "aria-hidden": true }),
1178
+ (onEdit || onUpload) && /* @__PURE__ */ jsx11("div", { className: "astrum-avatar__edit-icon", "aria-hidden": true, children: /* @__PURE__ */ jsx11(EditIcon, {}) })
1179
+ ] }),
1180
+ onRemove && /* @__PURE__ */ jsx11(
1181
+ "button",
1182
+ {
1183
+ type: "button",
1184
+ className: "astrum-avatar__remove-button",
1185
+ onClick: handleRemove,
1186
+ "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0430\u0432\u0430\u0442\u0430\u0440",
1187
+ children: /* @__PURE__ */ jsx11(CrossIcon, {})
1188
+ }
1189
+ )
1190
+ ] }) : /* @__PURE__ */ jsxs10("div", { className: "astrum-avatar__body", children: [
1191
+ /* @__PURE__ */ jsx11("div", { className: "astrum-avatar__placeholder", "aria-hidden": true, children: /* @__PURE__ */ jsx11("span", { className: "astrum-avatar__user-icon", children: /* @__PURE__ */ jsx11(UserIcon, {}) }) }),
1192
+ /* @__PURE__ */ jsx11("div", { className: "astrum-avatar__overlay", "aria-hidden": true }),
1193
+ /* @__PURE__ */ jsx11("div", { className: "astrum-avatar__add-icon", "aria-hidden": true, children: /* @__PURE__ */ jsx11(EditIcon, {}) })
1194
+ ] })
1195
+ ]
1196
+ }
1197
+ );
1198
+ }
1199
+ );
1200
+ Avatar.displayName = "Avatar";
1201
+ export {
1202
+ Avatar,
1203
+ Button,
1204
+ Checkbox,
1205
+ Chips,
1206
+ ColorPicker,
1207
+ FileItem,
1208
+ FileUpload,
1209
+ Input,
1210
+ InputCode,
1211
+ Radio,
1212
+ RadioGroup,
1213
+ Select,
1214
+ Toggler
1215
+ };
1216
+ //# sourceMappingURL=index.mjs.map