@zelelo/iskra-ui 0.0.0-stage → 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1231 @@
1
+ // src/utils/utils.ts
2
+ var cx = (...classes) => classes.filter(Boolean).join(" ");
3
+ var toCss = (value) => typeof value === "number" ? `${value}px` : value;
4
+
5
+ // src/components/Accordion/context.ts
6
+ import { createContext } from "react";
7
+ var AccordionContext = createContext(null);
8
+ var AccordionItemContext = createContext(null);
9
+
10
+ // src/components/Accordion/hooks/useAccordionState.ts
11
+ import { useState } from "react";
12
+ var useAccordionState = ({
13
+ type,
14
+ defaultValue = [],
15
+ value: controlledValue,
16
+ onValueChange
17
+ }) => {
18
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
19
+ const isControlled = controlledValue !== void 0;
20
+ const openValues = isControlled ? controlledValue : uncontrolledValue;
21
+ const toggleItem = (itemValue) => {
22
+ const isCurrentlyOpen = openValues.includes(itemValue);
23
+ let nextValue;
24
+ if (type === "single") {
25
+ nextValue = isCurrentlyOpen ? [] : [itemValue];
26
+ } else {
27
+ nextValue = isCurrentlyOpen ? openValues.filter((v) => v !== itemValue) : [...openValues, itemValue];
28
+ }
29
+ if (!isControlled) {
30
+ setUncontrolledValue(nextValue);
31
+ }
32
+ onValueChange?.(nextValue);
33
+ };
34
+ return { openValues, toggleItem };
35
+ };
36
+
37
+ // src/components/Accordion/AccordionProvider/AccordionProvider.tsx
38
+ import { jsx } from "react/jsx-runtime";
39
+ var AccordionProvider = ({
40
+ type = "single",
41
+ defaultValue,
42
+ value,
43
+ onValueChange,
44
+ disabled,
45
+ children
46
+ }) => {
47
+ const { openValues, toggleItem } = useAccordionState({
48
+ type,
49
+ defaultValue,
50
+ value,
51
+ onValueChange
52
+ });
53
+ return /* @__PURE__ */ jsx(AccordionContext.Provider, { value: { openValues, toggleItem, disabled }, children });
54
+ };
55
+
56
+ // src/components/Accordion/Accordion.module.css
57
+ var Accordion_default = {
58
+ accordion: "Accordion_accordion",
59
+ item: "Accordion_item",
60
+ disabled: "Accordion_disabled",
61
+ header: "Accordion_header",
62
+ trigger: "Accordion_trigger",
63
+ icon: "Accordion_icon",
64
+ iconOpen: "Accordion_iconOpen",
65
+ contentWrapper: "Accordion_contentWrapper",
66
+ contentWrapperOpen: "Accordion_contentWrapperOpen",
67
+ contentInner: "Accordion_contentInner"
68
+ };
69
+
70
+ // src/components/Accordion/Accordion.tsx
71
+ import { jsx as jsx2 } from "react/jsx-runtime";
72
+ var Accordion = ({
73
+ type = "single",
74
+ defaultValue,
75
+ value,
76
+ onValueChange,
77
+ disabled,
78
+ className,
79
+ children,
80
+ ...props
81
+ }) => /* @__PURE__ */ jsx2(
82
+ AccordionProvider,
83
+ {
84
+ type,
85
+ defaultValue,
86
+ value,
87
+ onValueChange,
88
+ disabled,
89
+ children: /* @__PURE__ */ jsx2("div", { className: cx(Accordion_default.accordion, className), ...props, children })
90
+ }
91
+ );
92
+ Accordion.displayName = "Accordion";
93
+
94
+ // src/components/Accordion/hooks/useAccordionItem.ts
95
+ import { useContext } from "react";
96
+ var useAccordionItem = () => {
97
+ const context = useContext(AccordionItemContext);
98
+ if (!context) {
99
+ throw new Error("useAccordionItem \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0432\u043D\u0435 AccordionItem");
100
+ }
101
+ return context;
102
+ };
103
+
104
+ // src/components/Accordion/components/AccordionContent.tsx
105
+ import { jsx as jsx3 } from "react/jsx-runtime";
106
+ var AccordionContent = ({
107
+ className,
108
+ children,
109
+ ...props
110
+ }) => {
111
+ const { isOpen, baseId } = useAccordionItem();
112
+ return /* @__PURE__ */ jsx3(
113
+ "div",
114
+ {
115
+ id: `content-${baseId}`,
116
+ role: "region",
117
+ "aria-labelledby": `trigger-${baseId}`,
118
+ className: cx(Accordion_default.contentWrapper, isOpen && Accordion_default.contentWrapperOpen, className),
119
+ ...props,
120
+ children: /* @__PURE__ */ jsx3("div", { className: Accordion_default.contentInner, children })
121
+ }
122
+ );
123
+ };
124
+ AccordionContent.displayName = "AccordionContent";
125
+
126
+ // src/components/Accordion/AccordionProvider/AccordionItemProvider.tsx
127
+ import { useId } from "react";
128
+
129
+ // src/components/Accordion/hooks/useAccordion.ts
130
+ import { useContext as useContext2 } from "react";
131
+ var useAccordion = () => {
132
+ const context = useContext2(AccordionContext);
133
+ if (!context) {
134
+ throw new Error("useAccordion \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0432\u043D\u0435 Accordion");
135
+ }
136
+ return context;
137
+ };
138
+
139
+ // src/components/Accordion/AccordionProvider/AccordionItemProvider.tsx
140
+ import { jsx as jsx4 } from "react/jsx-runtime";
141
+ var AccordionItemProvider = ({
142
+ value,
143
+ disabled: itemDisabled,
144
+ children
145
+ }) => {
146
+ const { openValues, disabled: rootDisabled } = useAccordion();
147
+ const isOpen = openValues.includes(value);
148
+ const disabled = rootDisabled || itemDisabled;
149
+ const baseId = useId();
150
+ return /* @__PURE__ */ jsx4(AccordionItemContext.Provider, { value: { value, isOpen, baseId, disabled }, children });
151
+ };
152
+
153
+ // src/components/Accordion/components/AccordionItem.tsx
154
+ import { jsx as jsx5 } from "react/jsx-runtime";
155
+ var AccordionItem = ({
156
+ value,
157
+ disabled,
158
+ className,
159
+ children,
160
+ ...props
161
+ }) => /* @__PURE__ */ jsx5(AccordionItemProvider, { value, disabled, children: /* @__PURE__ */ jsx5("div", { className: cx(Accordion_default.item, disabled && Accordion_default.disabled, className), ...props, children }) });
162
+
163
+ // src/components/Accordion/components/AccordionTrigger.tsx
164
+ import { jsx as jsx6, jsxs } from "react/jsx-runtime";
165
+ var AccordionTrigger = ({
166
+ className,
167
+ children,
168
+ disabled: triggerDisabled,
169
+ ...props
170
+ }) => {
171
+ const { toggleItem } = useAccordion();
172
+ const { value, isOpen, baseId, disabled } = useAccordionItem();
173
+ const isDisabled = disabled || triggerDisabled;
174
+ return /* @__PURE__ */ jsx6("h3", { className: Accordion_default.header, children: /* @__PURE__ */ jsxs(
175
+ "button",
176
+ {
177
+ type: "button",
178
+ id: `trigger-${baseId}`,
179
+ "aria-expanded": isOpen,
180
+ "aria-controls": `content-${baseId}`,
181
+ disabled: isDisabled,
182
+ className: cx(Accordion_default.trigger, className),
183
+ onClick: () => toggleItem(value),
184
+ ...props,
185
+ children: [
186
+ children,
187
+ /* @__PURE__ */ jsx6(
188
+ "svg",
189
+ {
190
+ className: cx(Accordion_default.icon, isOpen && Accordion_default.iconOpen),
191
+ width: "16",
192
+ height: "16",
193
+ viewBox: "0 0 16 16",
194
+ fill: "none",
195
+ xmlns: "http://www.w3.org/2000/svg",
196
+ "aria-hidden": "true",
197
+ children: /* @__PURE__ */ jsx6(
198
+ "path",
199
+ {
200
+ d: "M4 6L8 10L12 6",
201
+ stroke: "currentColor",
202
+ strokeWidth: "2",
203
+ strokeLinecap: "round",
204
+ strokeLinejoin: "round"
205
+ }
206
+ )
207
+ }
208
+ )
209
+ ]
210
+ }
211
+ ) });
212
+ };
213
+ AccordionTrigger.displayName = "AccordionTrigger";
214
+
215
+ // src/components/Alert/Alert.tsx
216
+ import { useState as useState2 } from "react";
217
+
218
+ // src/components/Alert/Alert.module.css
219
+ var Alert_default = {
220
+ alert: "Alert_alert",
221
+ content: "Alert_content",
222
+ title: "Alert_title",
223
+ description: "Alert_description",
224
+ closeButton: "Alert_closeButton",
225
+ info: "Alert_info",
226
+ success: "Alert_success",
227
+ warning: "Alert_warning",
228
+ error: "Alert_error"
229
+ };
230
+
231
+ // src/components/Alert/Alert.tsx
232
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
233
+ var Alert = ({
234
+ variant = "info",
235
+ title,
236
+ closable = false,
237
+ onClose,
238
+ children,
239
+ className,
240
+ ...props
241
+ }) => {
242
+ const [visible, setVisible] = useState2(true);
243
+ if (!visible) {
244
+ return null;
245
+ }
246
+ const handleClose = () => {
247
+ setVisible(false);
248
+ onClose?.();
249
+ };
250
+ const classes = cx(Alert_default.alert, Alert_default[variant], className);
251
+ return /* @__PURE__ */ jsxs2("div", { className: classes, role: "alert", ...props, children: [
252
+ /* @__PURE__ */ jsxs2("div", { className: Alert_default.content, children: [
253
+ title && /* @__PURE__ */ jsx7("div", { className: Alert_default.title, children: title }),
254
+ title && /* @__PURE__ */ jsx7("div", { className: Alert_default.description, children })
255
+ ] }),
256
+ closable && /* @__PURE__ */ jsx7(
257
+ "button",
258
+ {
259
+ type: "button",
260
+ className: Alert_default.closeButton,
261
+ onClick: handleClose,
262
+ "aria-label": "Close alert",
263
+ children: "\xD7"
264
+ }
265
+ )
266
+ ] });
267
+ };
268
+ Alert.displayName = "Alert";
269
+
270
+ // src/components/Badge/Badge.module.css
271
+ var Badge_default = {
272
+ badge: "Badge_badge",
273
+ count: "Badge_count",
274
+ dot: "Badge_dot",
275
+ blue: "Badge_blue",
276
+ red: "Badge_red",
277
+ green: "Badge_green"
278
+ };
279
+
280
+ // src/components/Badge/Badge.tsx
281
+ import { jsx as jsx8 } from "react/jsx-runtime";
282
+ var formatCount = (count, max) => {
283
+ if (count > max) {
284
+ return `${max}+`;
285
+ }
286
+ return String(count);
287
+ };
288
+ var Badge = ({
289
+ color = "blue",
290
+ max = 999,
291
+ count,
292
+ className,
293
+ ...props
294
+ }) => {
295
+ const isDot = count === void 0;
296
+ const classes = cx(Badge_default.badge, isDot ? Badge_default.dot : Badge_default.count, Badge_default[color], className);
297
+ return /* @__PURE__ */ jsx8("span", { className: classes, ...props, children: isDot ? null : formatCount(count, max) });
298
+ };
299
+ Badge.displayName = "Badge";
300
+
301
+ // src/components/Button/Button.tsx
302
+ import { forwardRef } from "react";
303
+
304
+ // src/components/Button/Button.module.css
305
+ var Button_default = {
306
+ button: "Button_button",
307
+ primary: "Button_primary",
308
+ secondary: "Button_secondary",
309
+ sm: "Button_sm",
310
+ md: "Button_md",
311
+ lg: "Button_lg"
312
+ };
313
+
314
+ // src/components/Button/Button.tsx
315
+ import { jsx as jsx9 } from "react/jsx-runtime";
316
+ var Button = forwardRef(
317
+ ({ variant = "primary", size = "md", type = "button", className, ...props }, ref) => {
318
+ const classes = cx(Button_default.button, Button_default[variant], Button_default[size], className);
319
+ return /* @__PURE__ */ jsx9("button", { ref, type, className: classes, ...props });
320
+ }
321
+ );
322
+ Button.displayName = "Button";
323
+
324
+ // src/components/Checkbox/Checkbox.tsx
325
+ import { forwardRef as forwardRef2, useEffect, useId as useId2, useImperativeHandle, useRef } from "react";
326
+
327
+ // src/components/Checkbox/Checkbox.module.css
328
+ var Checkbox_default = {
329
+ sm: "Checkbox_sm",
330
+ md: "Checkbox_md",
331
+ lg: "Checkbox_lg",
332
+ root: "Checkbox_root",
333
+ label: "Checkbox_label",
334
+ input: "Checkbox_input",
335
+ disabled: "Checkbox_disabled",
336
+ required: "Checkbox_required",
337
+ error: "Checkbox_error"
338
+ };
339
+
340
+ // src/components/Checkbox/Checkbox.tsx
341
+ import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
342
+ var Checkbox = forwardRef2(
343
+ ({
344
+ size = "md",
345
+ label,
346
+ indeterminate,
347
+ error,
348
+ className,
349
+ disabled,
350
+ required,
351
+ id,
352
+ "aria-describedby": ariaDescribedBy,
353
+ ...props
354
+ }, ref) => {
355
+ const innerRef = useRef(null);
356
+ const autoId = useId2();
357
+ const checkboxId = id ?? autoId;
358
+ const hasError = Boolean(error);
359
+ const messageId = hasError ? `${checkboxId}-message` : void 0;
360
+ const describeBy = [ariaDescribedBy, messageId].filter(Boolean).join(" ") || void 0;
361
+ useImperativeHandle(ref, () => innerRef.current, []);
362
+ useEffect(() => {
363
+ if (innerRef.current) {
364
+ innerRef.current.indeterminate = Boolean(indeterminate);
365
+ }
366
+ }, [indeterminate]);
367
+ return /* @__PURE__ */ jsxs3("div", { className: cx(Checkbox_default.root, Checkbox_default[size], disabled && Checkbox_default.disabled, className), children: [
368
+ /* @__PURE__ */ jsxs3("label", { className: Checkbox_default.label, children: [
369
+ /* @__PURE__ */ jsx10(
370
+ "input",
371
+ {
372
+ id: checkboxId,
373
+ ref: innerRef,
374
+ type: "checkbox",
375
+ className: Checkbox_default.input,
376
+ disabled,
377
+ required,
378
+ "aria-invalid": hasError || void 0,
379
+ "aria-describedby": describeBy,
380
+ ...props
381
+ }
382
+ ),
383
+ label,
384
+ required && /* @__PURE__ */ jsx10("span", { className: Checkbox_default.required, "aria-hidden": "true", children: " *" })
385
+ ] }),
386
+ hasError && /* @__PURE__ */ jsx10("p", { id: messageId, className: Checkbox_default.error, children: error })
387
+ ] });
388
+ }
389
+ );
390
+ Checkbox.displayName = "Checkbox";
391
+
392
+ // src/components/Input/Input.tsx
393
+ import { forwardRef as forwardRef3, useId as useId3 } from "react";
394
+
395
+ // src/components/Input/Input.module.css
396
+ var Input_default = {
397
+ sm: "Input_sm",
398
+ md: "Input_md",
399
+ lg: "Input_lg",
400
+ root: "Input_root",
401
+ label: "Input_label",
402
+ required: "Input_required",
403
+ field: "Input_field",
404
+ disabled: "Input_disabled",
405
+ invalid: "Input_invalid",
406
+ input: "Input_input",
407
+ icon: "Input_icon",
408
+ message: "Input_message",
409
+ error: "Input_error"
410
+ };
411
+
412
+ // src/components/Input/Input.tsx
413
+ import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
414
+ var Input = forwardRef3(
415
+ ({
416
+ size = "md",
417
+ label,
418
+ hint,
419
+ error,
420
+ startIcon,
421
+ endIcon,
422
+ className,
423
+ id,
424
+ required,
425
+ disabled,
426
+ "aria-describedby": ariaDescribedBy,
427
+ ...props
428
+ }, ref) => {
429
+ const autoId = useId3();
430
+ const inputId = id ?? autoId;
431
+ const hasError = Boolean(error);
432
+ const message = hasError ? error : hint;
433
+ const messageId = message ? `${inputId}-message` : void 0;
434
+ const describeBy = [ariaDescribedBy, messageId].filter(Boolean).join(" ") || void 0;
435
+ return /* @__PURE__ */ jsxs4("div", { className: cx(Input_default.root, Input_default[size], className), children: [
436
+ label && /* @__PURE__ */ jsxs4("label", { htmlFor: inputId, className: Input_default.label, children: [
437
+ label,
438
+ " ",
439
+ required && /* @__PURE__ */ jsx11("span", { className: Input_default.required, "aria-hidden": "true", children: " *" })
440
+ ] }),
441
+ /* @__PURE__ */ jsxs4("div", { className: cx(Input_default.field, hasError && Input_default.invalid, disabled && Input_default.disabled), children: [
442
+ startIcon && /* @__PURE__ */ jsx11("span", { className: Input_default.icon, children: startIcon }),
443
+ /* @__PURE__ */ jsx11(
444
+ "input",
445
+ {
446
+ ref,
447
+ id: inputId,
448
+ required,
449
+ disabled,
450
+ "aria-invalid": hasError || void 0,
451
+ "aria-describedby": describeBy,
452
+ className: Input_default.input,
453
+ ...props
454
+ }
455
+ ),
456
+ endIcon && /* @__PURE__ */ jsx11("span", { className: Input_default.icon, children: endIcon })
457
+ ] }),
458
+ message && /* @__PURE__ */ jsx11("p", { id: messageId, className: cx(Input_default.message, hasError && Input_default.error), children: message })
459
+ ] });
460
+ }
461
+ );
462
+ Input.displayName = "Input";
463
+
464
+ // src/components/Modal/Modal.tsx
465
+ import { useEffect as useEffect2, useId as useId4, useRef as useRef2 } from "react";
466
+
467
+ // src/components/Modal/Modal.module.css
468
+ var Modal_default = {
469
+ modal: "Modal_modal",
470
+ "modal-in": "Modal_modal-in",
471
+ "fade-in": "Modal_fade-in",
472
+ sm: "Modal_sm",
473
+ md: "Modal_md",
474
+ lg: "Modal_lg",
475
+ content: "Modal_content",
476
+ header: "Modal_header",
477
+ title: "Modal_title",
478
+ close: "Modal_close",
479
+ body: "Modal_body",
480
+ footer: "Modal_footer"
481
+ };
482
+
483
+ // src/components/Modal/Modal.tsx
484
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
485
+ var Modal = ({
486
+ open,
487
+ onClose,
488
+ title,
489
+ footer,
490
+ size = "md",
491
+ width,
492
+ children
493
+ }) => {
494
+ const ref = useRef2(null);
495
+ const titleId = useId4();
496
+ useEffect2(() => {
497
+ if (open) {
498
+ ref.current?.showModal();
499
+ } else {
500
+ ref.current?.close();
501
+ }
502
+ }, [open]);
503
+ const close = () => ref.current?.close();
504
+ return (
505
+ // Escape у <dialog> уже закрывает модалку с клавиатуры
506
+ // oxlint-disable-next-line jsx-a11y/click-events-have-key-events jsx-a11y/no-noninteractive-element-interactions
507
+ /* @__PURE__ */ jsx12(
508
+ "dialog",
509
+ {
510
+ ref,
511
+ className: cx(Modal_default.modal, Modal_default[size]),
512
+ style: { maxWidth: toCss(width) },
513
+ "aria-labelledby": title ? titleId : void 0,
514
+ onClose,
515
+ onClick: (e) => e.target === e.currentTarget && close(),
516
+ children: /* @__PURE__ */ jsxs5("div", { className: Modal_default.content, children: [
517
+ title && /* @__PURE__ */ jsxs5("header", { className: Modal_default.header, children: [
518
+ /* @__PURE__ */ jsx12("h2", { id: titleId, className: Modal_default.title, children: title }),
519
+ /* @__PURE__ */ jsx12("button", { type: "button", className: Modal_default.close, "aria-label": "\u0417\u0430\u043A\u0440\u044B\u0442\u044C", onClick: close, children: "\xD7" })
520
+ ] }),
521
+ /* @__PURE__ */ jsx12("div", { className: Modal_default.body, children }),
522
+ footer && /* @__PURE__ */ jsx12("footer", { className: Modal_default.footer, children: footer })
523
+ ] })
524
+ }
525
+ )
526
+ );
527
+ };
528
+ Modal.displayName = "Modal";
529
+
530
+ // src/components/Radio/Radio.tsx
531
+ import { forwardRef as forwardRef4, useContext as useContext3, useId as useId5 } from "react";
532
+
533
+ // src/components/RadioGroup/RadioGroupProvider/context.ts
534
+ import { createContext as createContext2 } from "react";
535
+ var RadioGroupContext = createContext2(null);
536
+
537
+ // src/components/Radio/Radio.module.css
538
+ var Radio_default = {
539
+ sm: "Radio_sm",
540
+ md: "Radio_md",
541
+ lg: "Radio_lg",
542
+ root: "Radio_root",
543
+ label: "Radio_label",
544
+ input: "Radio_input",
545
+ hasError: "Radio_hasError",
546
+ disabled: "Radio_disabled",
547
+ required: "Radio_required",
548
+ error: "Radio_error"
549
+ };
550
+
551
+ // src/components/Radio/Radio.tsx
552
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
553
+ var Radio = forwardRef4(
554
+ ({
555
+ size = "md",
556
+ label,
557
+ error,
558
+ className,
559
+ disabled,
560
+ required,
561
+ id,
562
+ name,
563
+ value,
564
+ checked,
565
+ onChange,
566
+ "aria-describedby": ariaDescribedBy,
567
+ ...props
568
+ }, ref) => {
569
+ const group = useContext3(RadioGroupContext);
570
+ const autoId = useId5();
571
+ const radioId = id ?? autoId;
572
+ const hasError = Boolean(error);
573
+ const messageId = hasError ? `${radioId}-message` : void 0;
574
+ const describeBy = [ariaDescribedBy, messageId].filter(Boolean).join(" ") || void 0;
575
+ const inputName = group ? group.name : name;
576
+ const isChecked = group ? group.value === String(value) : checked;
577
+ const isDisabled = group?.disabled || disabled;
578
+ const isRequired = group ? group.required : required;
579
+ const handleChange = (event) => {
580
+ onChange?.(event);
581
+ group?.onChange(event.target.value);
582
+ };
583
+ return /* @__PURE__ */ jsxs6(
584
+ "div",
585
+ {
586
+ className: cx(
587
+ Radio_default.root,
588
+ Radio_default[size],
589
+ disabled && Radio_default.disabled,
590
+ hasError && Radio_default.hasError,
591
+ className
592
+ ),
593
+ children: [
594
+ /* @__PURE__ */ jsxs6("label", { className: Radio_default.label, children: [
595
+ /* @__PURE__ */ jsx13(
596
+ "input",
597
+ {
598
+ ref,
599
+ id: radioId,
600
+ name: inputName,
601
+ type: "radio",
602
+ value,
603
+ checked: isChecked,
604
+ onChange: handleChange,
605
+ className: Radio_default.input,
606
+ disabled: isDisabled,
607
+ required: isRequired,
608
+ "aria-describedby": describeBy,
609
+ ...props
610
+ }
611
+ ),
612
+ label,
613
+ required && !group && /* @__PURE__ */ jsx13("span", { className: Radio_default.required, "aria-hidden": "true", children: " *" })
614
+ ] }),
615
+ hasError && /* @__PURE__ */ jsx13("p", { id: messageId, className: Radio_default.error, children: error })
616
+ ]
617
+ }
618
+ );
619
+ }
620
+ );
621
+ Radio.displayName = "Radio";
622
+
623
+ // src/components/RadioGroup/RadioGroup.tsx
624
+ import { useId as useId7 } from "react";
625
+
626
+ // src/components/RadioGroup/RadioGroupProvider/RadioGroupProvider.tsx
627
+ import { useId as useId6, useState as useState3 } from "react";
628
+ import { jsx as jsx14 } from "react/jsx-runtime";
629
+ var RadioGroupProvider = ({
630
+ name,
631
+ value: controlledValue,
632
+ defaultValue,
633
+ onChange,
634
+ disabled,
635
+ required,
636
+ children
637
+ }) => {
638
+ const [uncontrolledValue, setUncontrolledValue] = useState3(defaultValue);
639
+ const isControlled = controlledValue !== void 0;
640
+ const currentValue = isControlled ? controlledValue : uncontrolledValue;
641
+ const autoId = useId6();
642
+ const finalName = name ?? `radiogroup-${autoId}`;
643
+ const handleChange = (newValue) => {
644
+ if (!isControlled) {
645
+ setUncontrolledValue(newValue);
646
+ }
647
+ onChange?.(newValue);
648
+ };
649
+ return /* @__PURE__ */ jsx14(
650
+ RadioGroupContext.Provider,
651
+ {
652
+ value: {
653
+ name: finalName,
654
+ value: currentValue,
655
+ onChange: handleChange,
656
+ disabled,
657
+ required
658
+ },
659
+ children
660
+ }
661
+ );
662
+ };
663
+
664
+ // src/components/RadioGroup/RadioGroup.module.css
665
+ var RadioGroup_default = {
666
+ root: "RadioGroup_root",
667
+ disabled: "RadioGroup_disabled",
668
+ groupLabel: "RadioGroup_groupLabel",
669
+ required: "RadioGroup_required",
670
+ options: "RadioGroup_options",
671
+ error: "RadioGroup_error"
672
+ };
673
+
674
+ // src/components/RadioGroup/RadioGroup.tsx
675
+ import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
676
+ var RadioGroup = ({
677
+ value,
678
+ defaultValue,
679
+ onChange,
680
+ name,
681
+ label,
682
+ error,
683
+ required,
684
+ disabled,
685
+ className,
686
+ children,
687
+ ...props
688
+ }) => {
689
+ const labelId = useId7();
690
+ const messageId = useId7();
691
+ const hasError = Boolean(error);
692
+ return /* @__PURE__ */ jsx15(
693
+ RadioGroupProvider,
694
+ {
695
+ name,
696
+ value,
697
+ defaultValue,
698
+ onChange,
699
+ disabled,
700
+ required,
701
+ children: /* @__PURE__ */ jsxs7(
702
+ "div",
703
+ {
704
+ className: cx(RadioGroup_default.root, disabled && RadioGroup_default.disabled, className),
705
+ role: "radiogroup",
706
+ "aria-labelledby": label ? labelId : void 0,
707
+ "aria-invalid": hasError || void 0,
708
+ "aria-describedby": hasError ? messageId : void 0,
709
+ "aria-required": required || void 0,
710
+ ...props,
711
+ children: [
712
+ label && /* @__PURE__ */ jsxs7("div", { id: labelId, className: RadioGroup_default.groupLabel, children: [
713
+ label,
714
+ required && /* @__PURE__ */ jsx15("span", { className: RadioGroup_default.required, "aria-hidden": "true", children: " *" })
715
+ ] }),
716
+ /* @__PURE__ */ jsx15("div", { className: RadioGroup_default.options, children }),
717
+ hasError && /* @__PURE__ */ jsx15("p", { id: messageId, className: RadioGroup_default.error, children: error })
718
+ ]
719
+ }
720
+ )
721
+ }
722
+ );
723
+ };
724
+ RadioGroup.displayName = "RadioGroup";
725
+
726
+ // src/components/Skeleton/Skeleton.module.css
727
+ var Skeleton_default = {
728
+ skeleton: "Skeleton_skeleton",
729
+ text: "Skeleton_text",
730
+ rect: "Skeleton_rect",
731
+ circle: "Skeleton_circle",
732
+ lines: "Skeleton_lines",
733
+ withChildren: "Skeleton_withChildren",
734
+ hidden: "Skeleton_hidden",
735
+ pulse: "Skeleton_pulse",
736
+ wave: "Skeleton_wave"
737
+ };
738
+
739
+ // src/components/Skeleton/Skeleton.tsx
740
+ import { jsx as jsx16 } from "react/jsx-runtime";
741
+ var Skeleton = ({
742
+ variant = "text",
743
+ width,
744
+ height,
745
+ radius,
746
+ lines = 1,
747
+ animation = "pulse",
748
+ loading = true,
749
+ className,
750
+ style,
751
+ children,
752
+ ...props
753
+ }) => {
754
+ if (!loading) {
755
+ return children;
756
+ }
757
+ const baseClasses = cx(Skeleton_default.skeleton, Skeleton_default[variant], Skeleton_default[animation]);
758
+ const sizeStyle = {
759
+ width: toCss(width),
760
+ height: toCss(variant === "circle" ? height ?? width : height),
761
+ borderRadius: toCss(radius)
762
+ };
763
+ if (variant === "text" && lines > 1) {
764
+ return /* @__PURE__ */ jsx16(
765
+ "span",
766
+ {
767
+ className: cx(Skeleton_default.lines, className),
768
+ style: { width: sizeStyle.width, ...style },
769
+ "aria-hidden": "true",
770
+ ...props,
771
+ children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx16(
772
+ "span",
773
+ {
774
+ className: baseClasses,
775
+ style: { ...sizeStyle, width: i === lines - 1 ? "70%" : "100%" }
776
+ },
777
+ i
778
+ ))
779
+ }
780
+ );
781
+ }
782
+ return /* @__PURE__ */ jsx16(
783
+ "span",
784
+ {
785
+ className: cx(baseClasses, children != null && Skeleton_default.withChildren, className),
786
+ style: { ...sizeStyle, ...style },
787
+ "aria-hidden": "true",
788
+ ...props,
789
+ children: children != null && /* @__PURE__ */ jsx16("span", { className: Skeleton_default.hidden, children })
790
+ }
791
+ );
792
+ };
793
+ Skeleton.displayName = "Skeleton";
794
+
795
+ // src/components/Spinner/constants.ts
796
+ var SPINNER_VARIANTS = {
797
+ circle: { items: 0 },
798
+ dots: { items: 3 },
799
+ spiral: { items: 5 },
800
+ propagate: { items: 6 }
801
+ };
802
+
803
+ // src/components/Spinner/Spinner.module.css
804
+ var Spinner_default = {
805
+ spinner: "Spinner_spinner",
806
+ sm: "Spinner_sm",
807
+ md: "Spinner_md",
808
+ lg: "Spinner_lg",
809
+ item: "Spinner_item",
810
+ circle: "Spinner_circle",
811
+ spin: "Spinner_spin",
812
+ dots: "Spinner_dots",
813
+ beat: "Spinner_beat",
814
+ spiral: "Spinner_spiral",
815
+ propagate: "Spinner_propagate"
816
+ };
817
+
818
+ // src/components/Spinner/Spinner.tsx
819
+ import { jsx as jsx17 } from "react/jsx-runtime";
820
+ var Spinner = ({
821
+ variant = "circle",
822
+ size = "md",
823
+ label = "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430",
824
+ color,
825
+ className,
826
+ style,
827
+ ...props
828
+ }) => {
829
+ const { items } = SPINNER_VARIANTS[variant];
830
+ return /* @__PURE__ */ jsx17(
831
+ "span",
832
+ {
833
+ role: "status",
834
+ "aria-label": label,
835
+ className: cx(Spinner_default.spinner, Spinner_default[variant], Spinner_default[size], className),
836
+ style: { ...style, ...color && { color } },
837
+ ...props,
838
+ children: Array.from({ length: items }, (_, i) => /* @__PURE__ */ jsx17("span", { className: Spinner_default.item, style: { "--i": i } }, i))
839
+ }
840
+ );
841
+ };
842
+ Spinner.displayName = "Spinner";
843
+
844
+ // src/components/Switch/Switch.tsx
845
+ import { forwardRef as forwardRef5 } from "react";
846
+
847
+ // src/components/Switch/Switch.module.css
848
+ var Switch_default = {
849
+ sm: "Switch_sm",
850
+ md: "Switch_md",
851
+ lg: "Switch_lg",
852
+ root: "Switch_root",
853
+ input: "Switch_input",
854
+ track: "Switch_track",
855
+ thumb: "Switch_thumb",
856
+ disabled: "Switch_disabled"
857
+ };
858
+
859
+ // src/components/Switch/Switch.tsx
860
+ import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
861
+ var Switch = forwardRef5(
862
+ ({ size = "md", label, className, disabled, ...props }, ref) => /* @__PURE__ */ jsxs8("label", { className: cx(Switch_default.root, Switch_default[size], disabled && Switch_default.disabled, className), children: [
863
+ /* @__PURE__ */ jsx18(
864
+ "input",
865
+ {
866
+ ref,
867
+ "aria-checked": true,
868
+ type: "checkbox",
869
+ role: "switch",
870
+ disabled,
871
+ className: Switch_default.input,
872
+ ...props
873
+ }
874
+ ),
875
+ /* @__PURE__ */ jsx18("span", { className: Switch_default.track, "aria-hidden": "true", children: /* @__PURE__ */ jsx18("span", { className: Switch_default.thumb }) }),
876
+ label && /* @__PURE__ */ jsx18("span", { className: Switch_default.label, children: label })
877
+ ] })
878
+ );
879
+
880
+ // src/components/Tabs/Tabs.tsx
881
+ import { useId as useId8, useRef as useRef3, useState as useState4 } from "react";
882
+
883
+ // src/components/Tabs/Tabs.module.css
884
+ var Tabs_default = {
885
+ tabs: "Tabs_tabs",
886
+ list: "Tabs_list",
887
+ tab: "Tabs_tab",
888
+ panel: "Tabs_panel"
889
+ };
890
+
891
+ // src/components/Tabs/Tabs.tsx
892
+ import { jsx as jsx19, jsxs as jsxs9 } from "react/jsx-runtime";
893
+ var Tabs = ({ items, defaultValue, onChange, className }) => {
894
+ const [active, setActive] = useState4(() => {
895
+ const isSelectable = items.some((item) => item.value === defaultValue && !item.disabled);
896
+ return isSelectable ? defaultValue : items.find((item) => !item.disabled)?.value;
897
+ });
898
+ const id = useId8();
899
+ const tabRefs = useRef3([]);
900
+ const activeIndex = items.findIndex((item) => item.value === active);
901
+ const select = (value) => {
902
+ if (value === active) return;
903
+ setActive(value);
904
+ onChange?.(value);
905
+ };
906
+ const handleKeyDown = (event, index) => {
907
+ const enabled = items.flatMap((item, i) => item.disabled ? [] : [i]);
908
+ const position = enabled.indexOf(index);
909
+ let next;
910
+ switch (event.key) {
911
+ case "ArrowRight":
912
+ next = enabled[(position + 1) % enabled.length];
913
+ break;
914
+ case "ArrowLeft":
915
+ next = enabled[(position - 1 + enabled.length) % enabled.length];
916
+ break;
917
+ case "Home":
918
+ next = enabled[0];
919
+ break;
920
+ case "End":
921
+ next = enabled[enabled.length - 1];
922
+ break;
923
+ default:
924
+ return;
925
+ }
926
+ event.preventDefault();
927
+ tabRefs.current[next]?.focus();
928
+ select(items[next].value);
929
+ };
930
+ return /* @__PURE__ */ jsxs9("div", { className: cx(Tabs_default.tabs, className), children: [
931
+ /* @__PURE__ */ jsx19("div", { role: "tablist", className: Tabs_default.list, children: items.map((item, index) => {
932
+ const selected = index === activeIndex;
933
+ return /* @__PURE__ */ jsx19(
934
+ "button",
935
+ {
936
+ ref: (el) => {
937
+ tabRefs.current[index] = el;
938
+ },
939
+ type: "button",
940
+ role: "tab",
941
+ id: `${id}-tab-${index}`,
942
+ "aria-selected": selected,
943
+ "aria-controls": `${id}-panel`,
944
+ tabIndex: selected ? 0 : -1,
945
+ disabled: item.disabled,
946
+ className: Tabs_default.tab,
947
+ onClick: () => select(item.value),
948
+ onKeyDown: (event) => handleKeyDown(event, index),
949
+ children: item.label
950
+ },
951
+ item.value
952
+ );
953
+ }) }),
954
+ /* @__PURE__ */ jsx19(
955
+ "div",
956
+ {
957
+ role: "tabpanel",
958
+ id: `${id}-panel`,
959
+ "aria-labelledby": activeIndex >= 0 ? `${id}-tab-${activeIndex}` : void 0,
960
+ tabIndex: 0,
961
+ className: Tabs_default.panel,
962
+ children: items[activeIndex]?.content
963
+ }
964
+ )
965
+ ] });
966
+ };
967
+
968
+ // src/components/Toast/Toast.tsx
969
+ import { useCallback, useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
970
+
971
+ // src/components/Toast/Toast.module.css
972
+ var Toast_default = {
973
+ toast: "Toast_toast",
974
+ "toast-in": "Toast_toast-in",
975
+ content: "Toast_content",
976
+ title: "Toast_title",
977
+ description: "Toast_description",
978
+ closeButton: "Toast_closeButton",
979
+ info: "Toast_info",
980
+ success: "Toast_success",
981
+ warning: "Toast_warning",
982
+ error: "Toast_error"
983
+ };
984
+
985
+ // src/components/Toast/Toast.tsx
986
+ import { jsx as jsx20, jsxs as jsxs10 } from "react/jsx-runtime";
987
+ var Toast = ({
988
+ variant = "info",
989
+ title,
990
+ closable = true,
991
+ duration = 5e3,
992
+ onClose,
993
+ children,
994
+ className,
995
+ onMouseEnter,
996
+ onMouseLeave,
997
+ ...props
998
+ }) => {
999
+ const [visible, setVisible] = useState5(true);
1000
+ const timerRef = useRef4();
1001
+ const remainingRef = useRef4(duration);
1002
+ const startedAtRef = useRef4(0);
1003
+ const onCloseRef = useRef4(onClose);
1004
+ useEffect3(() => {
1005
+ onCloseRef.current = onClose;
1006
+ }, [onClose]);
1007
+ const handleClose = useCallback(() => {
1008
+ setVisible(false);
1009
+ onCloseRef.current?.();
1010
+ }, []);
1011
+ const clearTimer = useCallback(() => {
1012
+ if (timerRef.current) {
1013
+ clearTimeout(timerRef.current);
1014
+ timerRef.current = void 0;
1015
+ }
1016
+ }, []);
1017
+ const startTimer = useCallback(
1018
+ (ms) => {
1019
+ if (ms <= 0) return;
1020
+ startedAtRef.current = Date.now();
1021
+ timerRef.current = setTimeout(handleClose, ms);
1022
+ },
1023
+ [handleClose]
1024
+ );
1025
+ useEffect3(() => {
1026
+ startTimer(remainingRef.current);
1027
+ return clearTimer;
1028
+ }, [startTimer, clearTimer]);
1029
+ const handleMouseEnter = (e) => {
1030
+ clearTimer();
1031
+ remainingRef.current -= Date.now() - startedAtRef.current;
1032
+ onMouseEnter?.(e);
1033
+ };
1034
+ const handleMouseLeave = (e) => {
1035
+ startTimer(remainingRef.current);
1036
+ onMouseLeave?.(e);
1037
+ };
1038
+ if (!visible) {
1039
+ return null;
1040
+ }
1041
+ const classes = cx(Toast_default.toast, Toast_default[variant], className);
1042
+ return /* @__PURE__ */ jsxs10(
1043
+ "div",
1044
+ {
1045
+ className: classes,
1046
+ onMouseEnter: handleMouseEnter,
1047
+ onMouseLeave: handleMouseLeave,
1048
+ ...props,
1049
+ children: [
1050
+ /* @__PURE__ */ jsxs10("div", { className: Toast_default.content, role: "status", "aria-live": "polite", children: [
1051
+ title && /* @__PURE__ */ jsx20("div", { className: Toast_default.title, children: title }),
1052
+ children && /* @__PURE__ */ jsx20("div", { className: Toast_default.description, children })
1053
+ ] }),
1054
+ closable && /* @__PURE__ */ jsx20(
1055
+ "button",
1056
+ {
1057
+ type: "button",
1058
+ className: Toast_default.closeButton,
1059
+ onClick: handleClose,
1060
+ "aria-label": "Close toast",
1061
+ children: "\xD7"
1062
+ }
1063
+ )
1064
+ ]
1065
+ }
1066
+ );
1067
+ };
1068
+ Toast.displayName = "Button";
1069
+
1070
+ // src/components/Toast/ToastProvider/ToastProvider.tsx
1071
+ import { createContext as createContext3, useCallback as useCallback2, useMemo, useState as useState6 } from "react";
1072
+ import { createPortal } from "react-dom";
1073
+
1074
+ // src/components/Toast/ToastProvider/ToastContainer.module.css
1075
+ var ToastContainer_default = {
1076
+ container: "ToastContainer_container",
1077
+ "top-right": "ToastContainer_top-right",
1078
+ "top-left": "ToastContainer_top-left",
1079
+ "top-center": "ToastContainer_top-center",
1080
+ "bottom-right": "ToastContainer_bottom-right",
1081
+ "bottom-left": "ToastContainer_bottom-left",
1082
+ "bottom-center": "ToastContainer_bottom-center"
1083
+ };
1084
+
1085
+ // src/components/Toast/ToastProvider/ToastProvider.tsx
1086
+ import { jsx as jsx21, jsxs as jsxs11 } from "react/jsx-runtime";
1087
+ var idCounter = 0;
1088
+ var nextId = () => `toast-${Date.now()}-${idCounter++}`;
1089
+ var ToastContext = createContext3(null);
1090
+ var ToastProvider = ({
1091
+ children,
1092
+ position = "top-right"
1093
+ }) => {
1094
+ const [toasts, setToasts] = useState6([]);
1095
+ const close = useCallback2((id) => {
1096
+ setToasts((prev) => prev.filter((toast) => toast.id !== id));
1097
+ }, []);
1098
+ const show = useCallback2((options) => {
1099
+ const id = nextId();
1100
+ setToasts((prev) => [...prev, { id, ...options }]);
1101
+ return id;
1102
+ }, []);
1103
+ const value = useMemo(() => {
1104
+ return { show, close };
1105
+ }, [show, close]);
1106
+ return /* @__PURE__ */ jsxs11(ToastContext.Provider, { value, children: [
1107
+ children,
1108
+ typeof document !== "undefined" && createPortal(
1109
+ /* @__PURE__ */ jsx21("div", { className: cx(ToastContainer_default.container, ToastContainer_default[position]), children: toasts.map(({ id, description, ...rest }) => /* @__PURE__ */ jsx21(Toast, { ...rest, onClose: () => close(id), children: description }, id)) }),
1110
+ document.body
1111
+ )
1112
+ ] });
1113
+ };
1114
+
1115
+ // src/components/Toast/ToastProvider/hook/useToast.ts
1116
+ import { useContext as useContext4 } from "react";
1117
+ var useToast = () => {
1118
+ const ctx = useContext4(ToastContext);
1119
+ if (!ctx) {
1120
+ throw new Error("useToast \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0432\u043D\u0435 ToastProvider");
1121
+ }
1122
+ const make = (variant) => (options = {}) => ctx.show({ variant, ...options });
1123
+ return {
1124
+ show: ctx.show,
1125
+ close: ctx.close,
1126
+ info: make("info"),
1127
+ success: make("success"),
1128
+ warning: make("warning"),
1129
+ error: make("error")
1130
+ };
1131
+ };
1132
+
1133
+ // src/components/Tooltip/Tooltip.tsx
1134
+ import { cloneElement, isValidElement, useState as useState7 } from "react";
1135
+ import {
1136
+ autoUpdate,
1137
+ flip,
1138
+ offset,
1139
+ shift,
1140
+ useFloating,
1141
+ useFocus,
1142
+ useHover,
1143
+ useInteractions,
1144
+ useMergeRefs,
1145
+ useRole
1146
+ } from "@floating-ui/react";
1147
+
1148
+ // src/components/Tooltip/Tooltip.module.css
1149
+ var Tooltip_default = {
1150
+ tooltip: "Tooltip_tooltip",
1151
+ fadeIn: "Tooltip_fadeIn",
1152
+ arrow: "Tooltip_arrow"
1153
+ };
1154
+
1155
+ // src/components/Tooltip/Tooltip.tsx
1156
+ import { Fragment, jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
1157
+ var Tooltip = ({
1158
+ content,
1159
+ children,
1160
+ placement = "top",
1161
+ delay = 200,
1162
+ className,
1163
+ ...props
1164
+ }) => {
1165
+ const [open, setOpen] = useState7(false);
1166
+ const {
1167
+ refs,
1168
+ floatingStyles,
1169
+ context,
1170
+ placement: finalPlacement
1171
+ } = useFloating({
1172
+ open,
1173
+ onOpenChange: setOpen,
1174
+ placement,
1175
+ whileElementsMounted: autoUpdate,
1176
+ middleware: [offset(8), flip(), shift({ padding: 8 })]
1177
+ });
1178
+ const hover = useHover(context, { delay: { open: delay, close: 0 } });
1179
+ const focus = useFocus(context);
1180
+ const role = useRole(context, { role: "tooltip" });
1181
+ const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, role]);
1182
+ const childRef = isValidElement(children) ? children.props?.ref ?? children.ref : null;
1183
+ const mergedRef = useMergeRefs([refs.setReference, childRef]);
1184
+ const child = isValidElement(children) ? cloneElement(
1185
+ children,
1186
+ getReferenceProps({
1187
+ ...children.props,
1188
+ ref: mergedRef
1189
+ })
1190
+ ) : /* @__PURE__ */ jsx22("span", { ref: refs.setReference, ...getReferenceProps(), children });
1191
+ return /* @__PURE__ */ jsxs12(Fragment, { children: [
1192
+ child,
1193
+ open && /* @__PURE__ */ jsxs12(
1194
+ "div",
1195
+ {
1196
+ ref: refs.setFloating,
1197
+ style: floatingStyles,
1198
+ "data-placement": finalPlacement,
1199
+ className: cx(Tooltip_default.tooltip, className),
1200
+ ...getFloatingProps(props),
1201
+ children: [
1202
+ content,
1203
+ /* @__PURE__ */ jsx22("div", { className: Tooltip_default.arrow })
1204
+ ]
1205
+ }
1206
+ )
1207
+ ] });
1208
+ };
1209
+ export {
1210
+ Accordion,
1211
+ AccordionContent,
1212
+ AccordionItem,
1213
+ AccordionTrigger,
1214
+ Alert,
1215
+ Badge,
1216
+ Button,
1217
+ Checkbox,
1218
+ Input,
1219
+ Modal,
1220
+ Radio,
1221
+ RadioGroup,
1222
+ Skeleton,
1223
+ Spinner,
1224
+ Switch,
1225
+ Tabs,
1226
+ Toast,
1227
+ ToastProvider,
1228
+ Tooltip,
1229
+ useToast
1230
+ };
1231
+ //# sourceMappingURL=index.js.map