@phpsoftbox/react-softbox 0.2.0 → 0.4.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.
Files changed (55) hide show
  1. package/README.md +81 -1
  2. package/dist/components/Button/Button.d.ts +3 -1
  3. package/dist/components/Button/Button.js +16 -17
  4. package/dist/components/Button/Button.js.map +1 -1
  5. package/dist/components/FileUploader/FileUploader.d.ts +22 -0
  6. package/dist/components/FileUploader/FileUploader.js +156 -0
  7. package/dist/components/FileUploader/FileUploader.js.map +1 -0
  8. package/dist/components/FileUploader/FileUploader.module.css +142 -0
  9. package/dist/components/Input/Checkbox/Checkbox.d.ts +8 -0
  10. package/dist/components/Input/Checkbox/Checkbox.js +15 -0
  11. package/dist/components/Input/Checkbox/Checkbox.js.map +1 -0
  12. package/dist/components/Input/Checkbox/Checkbox.module.css +105 -0
  13. package/dist/components/Input/ErrorTooltip/ErrorTooltip.d.ts +12 -0
  14. package/dist/components/Input/ErrorTooltip/ErrorTooltip.js +25 -0
  15. package/dist/components/Input/ErrorTooltip/ErrorTooltip.js.map +1 -0
  16. package/dist/components/Input/ErrorTooltip/ErrorTooltip.module.css +31 -0
  17. package/dist/components/Input/Field.js +8 -1
  18. package/dist/components/Input/Field.js.map +1 -1
  19. package/dist/components/Input/FloatLabel/FloatLabel.module.css +11 -9
  20. package/dist/components/Input/FormField/FormField.d.ts +2 -0
  21. package/dist/components/Input/FormField/FormField.js +12 -1
  22. package/dist/components/Input/FormField/FormField.js.map +1 -1
  23. package/dist/components/Input/FormField/FormField.module.css +1 -0
  24. package/dist/components/Input/Input.d.ts +4 -0
  25. package/dist/components/Input/Input.js +4 -0
  26. package/dist/components/Input/Input.js.map +1 -1
  27. package/dist/components/Input/Input.module.css +8 -1
  28. package/dist/components/Input/Select/Select.d.ts +10 -5
  29. package/dist/components/Input/Select/Select.js +62 -16
  30. package/dist/components/Input/Select/Select.js.map +1 -1
  31. package/dist/components/Input/Select/Select.module.css +65 -23
  32. package/dist/components/Modal/Modal.d.ts +2 -1
  33. package/dist/components/Modal/Modal.js +18 -1
  34. package/dist/components/Modal/Modal.js.map +1 -1
  35. package/dist/components/Table/Table.d.ts +81 -0
  36. package/dist/components/Table/Table.js +240 -0
  37. package/dist/components/Table/Table.js.map +1 -0
  38. package/dist/components/Table/Table.module.css +236 -0
  39. package/dist/components/Tooltip/Tooltip.d.ts +33 -0
  40. package/dist/components/Tooltip/Tooltip.js +294 -0
  41. package/dist/components/Tooltip/Tooltip.js.map +1 -0
  42. package/dist/components/Tooltip/Tooltip.module.css +124 -0
  43. package/dist/{components/Button/Button.module.css → foundations/buttons.css} +47 -19
  44. package/dist/foundations/index.css +1 -0
  45. package/dist/foundations/tokens.css +6 -0
  46. package/dist/index.d.ts +6 -0
  47. package/dist/index.js +4 -0
  48. package/dist/index.js.map +1 -1
  49. package/docs/README.md +3 -1
  50. package/docs/forms.md +60 -0
  51. package/docs/layout.md +16 -0
  52. package/docs/overlays.md +2 -2
  53. package/docs/table.md +114 -0
  54. package/docs/tooltip.md +68 -0
  55. package/package.json +5 -1
@@ -0,0 +1,124 @@
1
+ .tooltip {
2
+ position: fixed;
3
+ z-index: 1200;
4
+ pointer-events: none;
5
+ opacity: 0;
6
+ transform: translateY(6px) scale(0.98);
7
+ transition: opacity 0.16s ease, transform 0.16s ease;
8
+ will-change: opacity, transform;
9
+ }
10
+
11
+ .tooltip[data-state='open'] {
12
+ opacity: 1;
13
+ transform: translateY(0) scale(1);
14
+ }
15
+
16
+ .interactive {
17
+ pointer-events: auto;
18
+ }
19
+
20
+ .bubble {
21
+ max-width: var(--tooltip-max-width, 280px);
22
+ background: var(--tooltip-bg, var(--surface-panel));
23
+ color: var(--tooltip-color, var(--color-text));
24
+ border: 1px solid var(--tooltip-border, var(--color-line));
25
+ border-radius: var(--radius-sm);
26
+ box-shadow: var(--shadow-soft);
27
+ padding: var(--spacing-2) var(--spacing-3);
28
+ font-size: var(--font-size-2);
29
+ line-height: 1.4;
30
+ position: relative;
31
+ }
32
+
33
+ .variantDefault {
34
+ --tooltip-bg: var(--surface-panel);
35
+ --tooltip-border: var(--color-line);
36
+ --tooltip-color: var(--color-text);
37
+ }
38
+
39
+ .variantInfo {
40
+ --tooltip-bg: rgba(20, 42, 76, 0.95);
41
+ --tooltip-border: rgba(64, 110, 200, 0.65);
42
+ --tooltip-color: #cfe0ff;
43
+ }
44
+
45
+ .variantSuccess {
46
+ --tooltip-bg: rgba(16, 59, 42, 0.95);
47
+ --tooltip-border: rgba(47, 186, 122, 0.6);
48
+ --tooltip-color: #d3f6e4;
49
+ }
50
+
51
+ .variantWarning {
52
+ --tooltip-bg: rgba(64, 46, 18, 0.95);
53
+ --tooltip-border: rgba(246, 200, 106, 0.6);
54
+ --tooltip-color: #ffe6b3;
55
+ }
56
+
57
+ .variantDanger {
58
+ --tooltip-bg: rgba(64, 26, 26, 0.95);
59
+ --tooltip-border: rgba(255, 107, 107, 0.7);
60
+ --tooltip-color: #ffd2d2;
61
+ }
62
+
63
+ .bubble::after {
64
+ content: '';
65
+ position: absolute;
66
+ width: 10px;
67
+ height: 10px;
68
+ background: var(--tooltip-bg, var(--surface-panel));
69
+ border: 1px solid var(--tooltip-border, var(--color-line));
70
+ transform: rotate(45deg);
71
+ }
72
+
73
+ .bubble[data-placement='top']::after {
74
+ left: 50%;
75
+ bottom: -6px;
76
+ transform: translateX(-50%) rotate(45deg);
77
+ border-left: none;
78
+ border-top: none;
79
+ }
80
+
81
+ .bubble[data-placement='bottom']::after {
82
+ left: 50%;
83
+ top: -6px;
84
+ transform: translateX(-50%) rotate(45deg);
85
+ border-right: none;
86
+ border-bottom: none;
87
+ }
88
+
89
+ .bubble[data-placement='left']::after {
90
+ top: 50%;
91
+ right: -6px;
92
+ transform: translateY(-50%) rotate(45deg);
93
+ border-left: none;
94
+ border-bottom: none;
95
+ }
96
+
97
+ .bubble[data-placement='right']::after {
98
+ top: 50%;
99
+ left: -6px;
100
+ transform: translateY(-50%) rotate(45deg);
101
+ border-right: none;
102
+ border-top: none;
103
+ }
104
+
105
+ .header {
106
+ font-weight: 600;
107
+ margin-bottom: var(--spacing-1);
108
+ }
109
+
110
+ .body {
111
+ font-size: inherit;
112
+ }
113
+
114
+ .footer {
115
+ margin-top: var(--spacing-2);
116
+ font-size: var(--font-size-2);
117
+ color: var(--color-muted);
118
+ }
119
+
120
+ @media (prefers-reduced-motion: reduce) {
121
+ .tooltip {
122
+ transition: none;
123
+ }
124
+ }
@@ -1,45 +1,73 @@
1
- .button {
1
+ .btn {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ gap: var(--spacing-2);
2
6
  border: 1px solid var(--btn-border, rgba(30, 51, 85, 0.6));
3
7
  cursor: pointer;
4
8
  font-weight: 600;
9
+ font-family: inherit;
10
+ line-height: 1;
5
11
  padding: 12px 18px;
6
12
  border-radius: var(--radius-sm);
13
+ font-size: var(--font-size-3);
7
14
  background: var(--btn-bg, rgba(15, 30, 51, 0.9));
8
15
  color: var(--btn-color, var(--color-text));
9
16
  box-shadow: var(--btn-shadow, none);
10
17
  transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease,
11
18
  color 0.2s ease;
19
+ text-decoration: none;
12
20
  }
13
21
 
14
- .button:focus-visible {
22
+ .btn:focus-visible {
15
23
  outline: none;
16
24
  box-shadow: 0 0 0 3px rgba(20, 201, 214, 0.3);
17
25
  }
18
26
 
19
- .button:hover:not(:disabled) {
27
+ .btn:hover:not(.btn-disabled):not(:disabled) {
20
28
  background: var(--btn-bg-hover, var(--btn-bg));
21
29
  box-shadow: var(--btn-shadow-hover, var(--btn-shadow, none));
22
30
  }
23
31
 
24
- .button:active:not(:disabled) {
32
+ .btn:active:not(.btn-disabled):not(:disabled) {
25
33
  transform: translateY(1px);
26
34
  }
27
35
 
28
- .button:disabled {
36
+ .btn:disabled,
37
+ .btn.btn-disabled {
29
38
  opacity: 0.6;
30
39
  cursor: not-allowed;
40
+ pointer-events: none;
31
41
  }
32
42
 
33
- .solid {
43
+ .btn-solid {
34
44
  transform: translateY(0);
35
45
  }
36
46
 
37
- .solid:hover:not(:disabled) {
47
+ .btn-solid:hover:not(.btn-disabled):not(:disabled) {
38
48
  transform: translateY(-1px);
39
49
  }
40
50
 
41
- .outline,
42
- .ghost {
51
+ .btn-sm {
52
+ padding: 8px 14px;
53
+ font-size: var(--font-size-2);
54
+ border-radius: var(--radius-xs);
55
+ }
56
+
57
+ .btn-md {
58
+ padding: 12px 18px;
59
+ font-size: var(--font-size-3);
60
+ border-radius: var(--radius-sm);
61
+ }
62
+
63
+ .btn-lg {
64
+ padding: 14px 22px;
65
+ font-size: var(--font-size-4);
66
+ border-radius: var(--radius-md);
67
+ }
68
+
69
+ .btn-outline,
70
+ .btn-ghost {
43
71
  background: transparent;
44
72
  color: var(--btn-accent, var(--color-teal));
45
73
  border-color: var(--btn-accent, var(--color-teal));
@@ -48,16 +76,16 @@
48
76
  --btn-shadow-hover: none;
49
77
  }
50
78
 
51
- .ghost {
79
+ .btn-ghost {
52
80
  border-color: transparent;
53
81
  }
54
82
 
55
- .outline:hover:not(:disabled),
56
- .ghost:hover:not(:disabled) {
83
+ .btn-outline:hover:not(.btn-disabled):not(:disabled),
84
+ .btn-ghost:hover:not(.btn-disabled):not(:disabled) {
57
85
  background: var(--btn-accent-soft, rgba(20, 201, 214, 0.12));
58
86
  }
59
87
 
60
- .variantDefault {
88
+ .btn-default {
61
89
  --btn-accent: var(--btn-default-accent, rgba(158, 178, 204, 0.9));
62
90
  --btn-accent-soft: var(--btn-default-soft, rgba(30, 51, 85, 0.35));
63
91
  --btn-bg: linear-gradient(135deg, var(--btn-default-start, #2a3750), var(--btn-default-end, #1b263c));
@@ -68,7 +96,7 @@
68
96
  --btn-shadow-hover: 0 14px 30px rgba(10, 20, 35, 0.28);
69
97
  }
70
98
 
71
- .variantPrimary {
99
+ .btn-primary {
72
100
  --btn-accent: var(--btn-primary-accent, rgba(20, 201, 214, 0.9));
73
101
  --btn-accent-soft: var(--btn-primary-soft, rgba(20, 201, 214, 0.18));
74
102
  --btn-bg: linear-gradient(135deg, var(--btn-primary-start, #14c9d6), var(--btn-primary-end, #1e63e9));
@@ -79,7 +107,7 @@
79
107
  --btn-shadow-hover: 0 16px 36px rgba(20, 201, 214, 0.4);
80
108
  }
81
109
 
82
- .variantInfo {
110
+ .btn-info {
83
111
  --btn-accent: var(--btn-info-accent, rgba(30, 99, 233, 0.9));
84
112
  --btn-accent-soft: var(--btn-info-soft, rgba(30, 99, 233, 0.18));
85
113
  --btn-bg: linear-gradient(135deg, var(--btn-info-start, #4f7bff), var(--btn-info-end, #2e5be6));
@@ -90,7 +118,7 @@
90
118
  --btn-shadow-hover: 0 16px 36px rgba(30, 99, 233, 0.4);
91
119
  }
92
120
 
93
- .variantSuccess {
121
+ .btn-success {
94
122
  --btn-accent: var(--btn-success-accent, rgba(79, 230, 163, 0.9));
95
123
  --btn-accent-soft: var(--btn-success-soft, rgba(79, 230, 163, 0.16));
96
124
  --btn-bg: linear-gradient(135deg, var(--btn-success-start, #35d092), var(--btn-success-end, #1faf75));
@@ -101,7 +129,7 @@
101
129
  --btn-shadow-hover: 0 16px 36px rgba(79, 230, 163, 0.36);
102
130
  }
103
131
 
104
- .variantWarning {
132
+ .btn-warning {
105
133
  --btn-accent: var(--btn-warning-accent, rgba(246, 200, 106, 0.95));
106
134
  --btn-accent-soft: var(--btn-warning-soft, rgba(246, 200, 106, 0.2));
107
135
  --btn-bg: linear-gradient(135deg, var(--btn-warning-start, #ffd166), var(--btn-warning-end, #f4a62a));
@@ -112,7 +140,7 @@
112
140
  --btn-shadow-hover: 0 16px 36px rgba(246, 200, 106, 0.36);
113
141
  }
114
142
 
115
- .variantDanger {
143
+ .btn-danger {
116
144
  --btn-accent: var(--btn-danger-accent, rgba(255, 107, 107, 0.95));
117
145
  --btn-accent-soft: var(--btn-danger-soft, rgba(255, 107, 107, 0.2));
118
146
  --btn-bg: linear-gradient(135deg, var(--btn-danger-start, #ff8f8f), var(--btn-danger-end, #ff5b5b));
@@ -124,7 +152,7 @@
124
152
  }
125
153
 
126
154
  @media (prefers-reduced-motion: reduce) {
127
- .button {
155
+ .btn {
128
156
  transition: none;
129
157
  }
130
158
  }
@@ -1,4 +1,5 @@
1
1
  @import "./tokens.css";
2
2
  @import "./typography.css";
3
3
  @import "./layout.css";
4
+ @import "./buttons.css";
4
5
  @import "./utilities.css";
@@ -135,6 +135,12 @@
135
135
  --spacing-8: 40px;
136
136
  --spacing-9: 48px;
137
137
  --spacing-10: 64px;
138
+
139
+ --ui-control-height: 48px;
140
+ --ui-control-padding-x: 16px;
141
+ --ui-control-padding-y: 12px;
142
+ --ui-control-font-size: var(--font-size-3);
143
+ --ui-control-line-height: 1.2;
138
144
  }
139
145
 
140
146
  :root[data-theme="light"] {
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export { default as Input } from './components/Input/Input';
7
7
  export { default as Textarea } from './components/Input/Textarea/Textarea';
8
8
  export { default as Radio } from './components/Input/Radio/Radio';
9
9
  export { default as Switch } from './components/Input/Switch/Switch';
10
+ export { default as Checkbox } from './components/Input/Checkbox/Checkbox';
10
11
  export { default as Select } from './components/Input/Select/Select';
11
12
  export { default as Alert } from './components/Alert/Alert';
12
13
  export { default as Notifier } from './components/Notifier/Notifier';
@@ -23,6 +24,11 @@ export { default as Tabs } from './components/Tabs/Tabs';
23
24
  export { default as Progress } from './components/Progress/Progress';
24
25
  export { default as Breadcrumbs } from './components/Breadcrumbs/Breadcrumbs';
25
26
  export { default as Image } from './components/Image/Image';
27
+ export { default as FileUploader } from './components/FileUploader/FileUploader';
28
+ export { default as Tooltip } from './components/Tooltip/Tooltip';
29
+ export { default as Table } from './components/Table/Table';
30
+ export type { TableBulkAction, TableBulkActions, TableColumn, TableRenderBulkAction, TableSelection, TableSortDirection, TableSortOptions, TableSortState, } from './components/Table/Table';
31
+ export type { TooltipPlacement, TooltipVariant } from './components/Tooltip/Tooltip';
26
32
  export { default as Text } from './components/Typography/Text';
27
33
  export { default as Heading } from './components/Typography/Heading';
28
34
  export { default as useMediaQuery } from './hooks/useMediaQuery';
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export { default as Input } from './components/Input/Input';
7
7
  export { default as Textarea } from './components/Input/Textarea/Textarea';
8
8
  export { default as Radio } from './components/Input/Radio/Radio';
9
9
  export { default as Switch } from './components/Input/Switch/Switch';
10
+ export { default as Checkbox } from './components/Input/Checkbox/Checkbox';
10
11
  export { default as Select } from './components/Input/Select/Select';
11
12
  export { default as Alert } from './components/Alert/Alert';
12
13
  export { default as Notifier } from './components/Notifier/Notifier';
@@ -23,6 +24,9 @@ export { default as Tabs } from './components/Tabs/Tabs';
23
24
  export { default as Progress } from './components/Progress/Progress';
24
25
  export { default as Breadcrumbs } from './components/Breadcrumbs/Breadcrumbs';
25
26
  export { default as Image } from './components/Image/Image';
27
+ export { default as FileUploader } from './components/FileUploader/FileUploader';
28
+ export { default as Tooltip } from './components/Tooltip/Tooltip';
29
+ export { default as Table } from './components/Table/Table';
26
30
  export { default as Text } from './components/Typography/Text';
27
31
  export { default as Heading } from './components/Typography/Heading';
28
32
  export { default as useMediaQuery } from './hooks/useMediaQuery';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,4CAA4C,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAY5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
package/docs/README.md CHANGED
@@ -28,7 +28,9 @@ import { Button, Card, Menu } from '@phpsoftbox/react-softbox';
28
28
 
29
29
  - `layout.md` — Grid, Flex, утилиты
30
30
  - `navigation.md` — Menu, Dropdown, CollapseButton
31
- - `forms.md` — Input (Field/Select/FloatLabel), Switch, Radio
31
+ - `forms.md` — Input (Field/Select/FloatLabel), Switch, Radio, Checkbox, FileUploader
32
+ - `table.md` — Table, сортировка, футер
33
+ - `tooltip.md` — Tooltip и варианты
32
34
  - `overlays.md` — Modal, Drawer
33
35
  - `feedback.md` — Badge, Alert, Notifier
34
36
  - `card.md` — Card и его секции
package/docs/forms.md CHANGED
@@ -20,6 +20,24 @@
20
20
  </Input>
21
21
  ```
22
22
 
23
+ ### Ошибка через Tooltip
24
+
25
+ ```tsx
26
+ <Input>
27
+ <Input.Label>Почта</Input.Label>
28
+ <Input.Control>
29
+ <Input.Field hasError placeholder="name@example.com" />
30
+ <Input.ErrorTooltip content="Некорректный email" />
31
+ </Input.Control>
32
+ </Input>
33
+
34
+ <Input>
35
+ <Input.Label>Телефон</Input.Label>
36
+ <Input.Field hasError placeholder="+7 (___) ___-__-__" />
37
+ <Input.ErrorTooltip target="input" content="Введите номер" placement="right" />
38
+ </Input>
39
+ ```
40
+
23
41
  ## Textarea
24
42
 
25
43
  ```tsx
@@ -41,6 +59,13 @@
41
59
  <Input.Radio name="mode" label="Резервный" />
42
60
  ```
43
61
 
62
+ ## Checkbox
63
+
64
+ ```tsx
65
+ <Input.Checkbox label="Согласен с условиями" />
66
+ <Input.Checkbox label="Премиум" description="Расширенные права" />
67
+ ```
68
+
44
69
  ## Switch
45
70
 
46
71
  ```tsx
@@ -90,6 +115,21 @@ const options = [
90
115
  </Input>
91
116
  ```
92
117
 
118
+ ### Пустое значение и сброс
119
+
120
+ ```tsx
121
+ <Input>
122
+ <Input.Label>Статус</Input.Label>
123
+ <Input.Select
124
+ options={options}
125
+ allowEmptyValue
126
+ emptyOptionLabel="Не выбрано"
127
+ searchable
128
+ clearable
129
+ />
130
+ </Input>
131
+ ```
132
+
93
133
  ### Загрузка через axios
94
134
 
95
135
  ```tsx
@@ -173,3 +213,23 @@ const options = [
173
213
  </Input.Group>
174
214
  </Input>
175
215
  ```
216
+
217
+ ## FileUploader
218
+
219
+ ```tsx
220
+ <FileUploader
221
+ allowedTypes={['.jpg', '.png', '.pdf']}
222
+ maxFileSizeKb={2048}
223
+ multiple
224
+ showPreview
225
+ onChange={(files) => console.log(files)}
226
+ onUpload={(files) => api.upload(files)}
227
+ />;
228
+ ```
229
+
230
+ Параметры:
231
+ - `allowedTypes` — допустимые типы (расширения `.png` или MIME `image/*`)
232
+ - `maxFileSizeKb` — ограничение размера
233
+ - `multiple` — разрешить множественный выбор
234
+ - `showPreview` — превью для изображений
235
+ - `onUpload` — колбэк загрузки (опционально)
package/docs/layout.md CHANGED
@@ -52,3 +52,19 @@
52
52
  - `p-`, `px-`, `py-`, `pt-`, `pr-`, `pb-`, `pl-`
53
53
  - `m-`, `mx-`, `my-`, `mt-`, `mr-`, `mb-`, `ml-`
54
54
  - `gap-`
55
+
56
+ ## Классы кнопок
57
+
58
+ Глобальные классы для кнопок, которые можно применять к `a`/`button`.
59
+
60
+ ```tsx
61
+ <a className="btn btn-primary btn-solid" href="/create">Создать</a>
62
+ <a className="btn btn-info btn-outline" href="/details">Подробнее</a>
63
+ <button className="btn btn-danger btn-ghost">Удалить</button>
64
+ ```
65
+
66
+ Доступны:
67
+ - базовый класс: `btn`
68
+ - варианты: `btn-default`, `btn-primary`, `btn-info`, `btn-success`, `btn-warning`, `btn-danger`
69
+ - внешность: `btn-solid`, `btn-outline`, `btn-ghost`
70
+ - размеры: `btn-sm`, `btn-md`, `btn-lg`
package/docs/overlays.md CHANGED
@@ -3,12 +3,12 @@
3
3
  ## Modal
4
4
 
5
5
  ```tsx
6
- <Modal open={open} title="Заголовок" onClose={() => setOpen(false)}>
6
+ <Modal open={open} title="Заголовок" lockScroll onClose={() => setOpen(false)}>
7
7
  Контент модалки
8
8
  </Modal>
9
9
  ```
10
10
 
11
- Поддерживает `footer` для действий.
11
+ Поддерживает `footer` для действий и `lockScroll` для блокировки скролла страницы (по умолчанию `true`).
12
12
 
13
13
  ## Drawer
14
14
 
package/docs/table.md ADDED
@@ -0,0 +1,114 @@
1
+ # Table
2
+
3
+ `Table` — табличный компонент с декларативными колонками, сортировкой и футером.
4
+
5
+ ## Базовый пример
6
+
7
+ ```tsx
8
+ const columns = [
9
+ { id: 'name', header: 'Название', accessor: 'name' },
10
+ { id: 'status', header: 'Статус', accessor: 'status' },
11
+ { id: 'amount', header: 'Сумма', accessor: (row) => `${row.amount} ₽`, align: 'right' },
12
+ ];
13
+
14
+ <Table columns={columns} data={rows} />;
15
+ ```
16
+
17
+ ## Колонки из бэкенда
18
+
19
+ ```tsx
20
+ const backendColumns = [
21
+ { id: 'client', title: 'Клиент', field: 'client', sortable: true },
22
+ { id: 'project', title: 'Проект', field: 'project' },
23
+ { id: 'amount', title: 'Сумма', field: 'amount', sortable: true, align: 'right' },
24
+ ];
25
+
26
+ <Table columns={backendColumns} data={rows} />;
27
+ ```
28
+
29
+ `header`, `label`, `title`, `field` используются по цепочке как заголовок. `accessor` может быть ключом или функцией.
30
+
31
+ ## Сортировка с обновлением query‑параметров
32
+
33
+ ```tsx
34
+ const [sort, setSort] = useState({ key: 'amount', direction: 'asc' });
35
+
36
+ <Table
37
+ columns={[
38
+ { id: 'client', header: 'Клиент', accessor: 'client', sortable: true },
39
+ { id: 'amount', header: 'Сумма', accessor: 'amount', sortable: true, align: 'right' },
40
+ ]}
41
+ data={rows}
42
+ sort={{
43
+ key: sort.key,
44
+ direction: sort.direction,
45
+ param: 'sort',
46
+ orderParam: 'order',
47
+ onChange: (next, url) => {
48
+ setSort(next);
49
+ window.history.replaceState(null, '', url);
50
+ },
51
+ }}
52
+ />;
53
+ ```
54
+
55
+ ## Футер
56
+
57
+ ```tsx
58
+ const columns = [
59
+ { id: 'name', header: 'Товар', accessor: 'name', footer: 'Итого' },
60
+ {
61
+ id: 'amount',
62
+ header: 'Сумма',
63
+ accessor: 'amount',
64
+ align: 'right',
65
+ footer: (rows) => rows.reduce((sum, row) => sum + row.amount, 0),
66
+ },
67
+ ];
68
+
69
+ <Table columns={columns} data={rows} showFooter />;
70
+ ```
71
+
72
+ ### Футер только в нужных колонках
73
+
74
+ ```tsx
75
+ const columns = [
76
+ { id: 'a', header: 'A', accessor: 'a' },
77
+ { id: 'b', header: 'B', accessor: 'b' },
78
+ { id: 'c', header: 'C', accessor: 'c' },
79
+ { id: 'd', header: 'D', accessor: 'd', footer: 'Итого' },
80
+ { id: 'e', header: 'E', accessor: 'e', footer: (rows) => rows.reduce((sum, row) => sum + row.e, 0) },
81
+ ];
82
+
83
+ <Table columns={columns} data={rows} showFooter />;
84
+ ```
85
+
86
+ ## Выбор строк + renderBulkAction
87
+
88
+ ```tsx
89
+ const [selected, setSelected] = useState<React.Key[]>([]);
90
+
91
+ <Table
92
+ columns={columns}
93
+ data={rows}
94
+ selection={{
95
+ selectedIds: selected,
96
+ onToggle: (id) => setSelected((prev) => prev.includes(id) ? prev.filter((key) => key !== id) : [...prev, id]),
97
+ onToggleAll: (ids) => setSelected((prev) => ids.length > 0 && ids.every((id) => prev.includes(id)) ? [] : ids),
98
+ }}
99
+ renderBulkAction={(ids) => (
100
+ <div>
101
+ Выбрано: {ids.length}
102
+ </div>
103
+ )}
104
+ />;
105
+ ```
106
+
107
+ ## Полезные поля колонки
108
+
109
+ - `field` / `accessor` / `cell` — источник данных
110
+ - `sortable`, `sortKey` — сортировка для колонки
111
+ - `footer` — значение в футере (node или функция)
112
+ - `hideOn` — скрыть колонку на `sm`/`md`/`lg`
113
+ - `width` / `minWidth` — размеры колонки
114
+ - `align` — `left` | `center` | `right`
@@ -0,0 +1,68 @@
1
+ # Tooltip
2
+
3
+ `Tooltip` — всплывающая подсказка для элементов интерфейса.
4
+
5
+ ## Базовый пример
6
+
7
+ ```tsx
8
+ <Tooltip content="Подсказка">
9
+ <Button>Наведи</Button>
10
+ </Tooltip>
11
+ ```
12
+
13
+ ## Направление
14
+
15
+ `placement`: `auto` | `top` | `bottom` | `left` | `right`.
16
+
17
+ ```tsx
18
+ <Tooltip content="Справа" placement="right">
19
+ <span>Help</span>
20
+ </Tooltip>
21
+ ```
22
+
23
+ ## Интерактивный контент
24
+
25
+ Если нужно, чтобы подсказка не исчезала при наведении мышью на сам tooltip (например, есть ссылки), включите `interactive`.
26
+
27
+ ```tsx
28
+ <Tooltip
29
+ interactive
30
+ content={
31
+ <>
32
+ <Tooltip.Header>Подробности</Tooltip.Header>
33
+ <Tooltip.Body>
34
+ Перейдите в <a href="/docs">документацию</a>.
35
+ </Tooltip.Body>
36
+ <Tooltip.Footer>Последнее обновление: сегодня</Tooltip.Footer>
37
+ </>
38
+ }
39
+ >
40
+ <Button>Подробнее</Button>
41
+ </Tooltip>
42
+ ```
43
+
44
+ ## Варианты
45
+
46
+ `variant`: `default` | `info` | `success` | `warning` | `danger`.
47
+
48
+ ```tsx
49
+ <Tooltip content="Важно" variant="warning">
50
+ <span>!</span>
51
+ </Tooltip>
52
+ ```
53
+
54
+ ## Header / Body / Footer
55
+
56
+ ```tsx
57
+ <Tooltip
58
+ content={
59
+ <>
60
+ <Tooltip.Header>Заголовок</Tooltip.Header>
61
+ <Tooltip.Body>Подробности и описание.</Tooltip.Body>
62
+ <Tooltip.Footer>Доп. инфо</Tooltip.Footer>
63
+ </>
64
+ }
65
+ >
66
+ <Button>Подробнее</Button>
67
+ </Tooltip>
68
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phpsoftbox/react-softbox",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,6 +42,10 @@
42
42
  "axios": "^1.12.2"
43
43
  },
44
44
  "devDependencies": {
45
+ "@testing-library/dom": "^10.4.1",
46
+ "@testing-library/jest-dom": "^6.9.1",
47
+ "@testing-library/react": "^16.3.2",
48
+ "@types/jest": "^30.0.0",
45
49
  "@types/react": "^19.2.0",
46
50
  "@types/react-dom": "^19.2.0",
47
51
  "typescript": "^5.9.3"