nexa-ui-kit 0.11.6 → 0.11.9

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 (95) hide show
  1. package/dist/components/NAlert.js +2 -14
  2. package/dist/components/NAlert.nexa +3 -14
  3. package/dist/components/NAutocomplete.js +1 -1
  4. package/dist/components/NAutocomplete.nexa +2 -1
  5. package/dist/components/NAvatar.js +0 -5
  6. package/dist/components/NAvatar.nexa +1 -5
  7. package/dist/components/NBadge.js +0 -6
  8. package/dist/components/NBadge.nexa +1 -6
  9. package/dist/components/NBottomSheet.js +0 -5
  10. package/dist/components/NBottomSheet.nexa +1 -5
  11. package/dist/components/NButton.js +219 -296
  12. package/dist/components/NButton.nexa +241 -320
  13. package/dist/components/NCard.js +39 -82
  14. package/dist/components/NCard.nexa +27 -71
  15. package/dist/components/NCheckbox.js +74 -63
  16. package/dist/components/NCheckbox.nexa +64 -44
  17. package/dist/components/NChips.nexa +1 -0
  18. package/dist/components/NDataTable.js +300 -356
  19. package/dist/components/NDataTable.nexa +265 -320
  20. package/dist/components/NDatepicker.js +4 -25
  21. package/dist/components/NDatepicker.nexa +5 -25
  22. package/dist/components/NForm.nexa +1 -0
  23. package/dist/components/NFormField.js +0 -5
  24. package/dist/components/NFormField.nexa +1 -5
  25. package/dist/components/NImage.js +1 -6
  26. package/dist/components/NImage.nexa +2 -6
  27. package/dist/components/NInput.js +96 -263
  28. package/dist/components/NInput.nexa +89 -259
  29. package/dist/components/NInputNumber.nexa +1 -1
  30. package/dist/components/NModal.js +1 -118
  31. package/dist/components/NModal.nexa +2 -119
  32. package/dist/components/NMultiSelect.js +1 -1
  33. package/dist/components/NMultiSelect.nexa +2 -1
  34. package/dist/components/NPaginator.js +1 -11
  35. package/dist/components/NPaginator.nexa +2 -11
  36. package/dist/components/NPassword.nexa +1 -0
  37. package/dist/components/NProgressBar.js +0 -11
  38. package/dist/components/NProgressBar.nexa +1 -11
  39. package/dist/components/NRadio.js +1 -8
  40. package/dist/components/NRadio.nexa +2 -8
  41. package/dist/components/NScrollView.js +0 -6
  42. package/dist/components/NScrollView.nexa +1 -6
  43. package/dist/components/NSelect.js +7 -35
  44. package/dist/components/NSelect.nexa +8 -35
  45. package/dist/components/NSkeleton.js +3 -9
  46. package/dist/components/NSkeleton.nexa +4 -9
  47. package/dist/components/NSwitch.js +0 -6
  48. package/dist/components/NSwitch.nexa +1 -6
  49. package/dist/components/NTabs.js +0 -11
  50. package/dist/components/NTabs.nexa +1 -11
  51. package/dist/components/NTag.js +1 -11
  52. package/dist/components/NTag.nexa +2 -11
  53. package/dist/components/NToastContainer.js +3 -27
  54. package/dist/components/NToastContainer.nexa +4 -27
  55. package/dist/components/NTooltip.js +0 -13
  56. package/dist/components/NTooltip.nexa +1 -13
  57. package/dist/components/NTreeMenu.js +1 -21
  58. package/dist/components/NTreeMenu.nexa +2 -21
  59. package/dist/components/NVirtualList.js +0 -2
  60. package/dist/components/NVirtualList.nexa +1 -2
  61. package/dist/styles/tokens.css +82 -173
  62. package/package.json +5 -5
  63. package/src/components/NAlert.nexa +3 -14
  64. package/src/components/NAutocomplete.nexa +2 -1
  65. package/src/components/NAvatar.nexa +1 -5
  66. package/src/components/NBadge.nexa +1 -6
  67. package/src/components/NBottomSheet.nexa +1 -5
  68. package/src/components/NButton.nexa +241 -320
  69. package/src/components/NCard.nexa +27 -71
  70. package/src/components/NCheckbox.nexa +64 -44
  71. package/src/components/NChips.nexa +1 -0
  72. package/src/components/NDataTable.nexa +265 -320
  73. package/src/components/NDatepicker.nexa +5 -25
  74. package/src/components/NForm.nexa +1 -0
  75. package/src/components/NFormField.nexa +1 -5
  76. package/src/components/NImage.nexa +2 -6
  77. package/src/components/NInput.nexa +89 -259
  78. package/src/components/NInputNumber.nexa +1 -1
  79. package/src/components/NModal.nexa +2 -119
  80. package/src/components/NMultiSelect.nexa +2 -1
  81. package/src/components/NPaginator.nexa +2 -11
  82. package/src/components/NPassword.nexa +1 -0
  83. package/src/components/NProgressBar.nexa +1 -11
  84. package/src/components/NRadio.nexa +2 -8
  85. package/src/components/NScrollView.nexa +1 -6
  86. package/src/components/NSelect.nexa +8 -35
  87. package/src/components/NSkeleton.nexa +4 -9
  88. package/src/components/NSwitch.nexa +1 -6
  89. package/src/components/NTabs.nexa +1 -11
  90. package/src/components/NTag.nexa +2 -11
  91. package/src/components/NToastContainer.nexa +4 -27
  92. package/src/components/NTooltip.nexa +1 -13
  93. package/src/components/NTreeMenu.nexa +2 -21
  94. package/src/components/NVirtualList.nexa +1 -2
  95. package/src/styles/tokens.css +82 -173
@@ -44,26 +44,22 @@ const initials = computed(() => {
44
44
  user-select: none;
45
45
  transition: all var(--n-transition-fast);
46
46
  border: 1px solid var(--n-color-border);
47
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
48
47
  }
49
-
50
48
  .is-sm { width: 32px; height: 32px; font-size: var(--n-text-xs); }
51
49
  .is-md { width: 40px; height: 40px; font-size: var(--n-text-sm); }
52
50
  .is-lg { width: 56px; height: 56px; font-size: var(--n-text-lg); }
53
51
  .is-xl { width: 72px; height: 72px; font-size: var(--n-text-2xl); }
54
-
55
52
  .is-circle { border-radius: var(--n-radius-full); }
56
53
  .is-rounded { border-radius: var(--n-radius-md); }
57
54
  .is-square { border-radius: 0; }
58
-
59
55
  .is-primary { background-color: var(--n-color-primary); color: white; }
60
56
  .is-success { background-color: var(--n-color-success); color: white; }
61
57
  .is-danger { background-color: var(--n-color-danger); color: white; }
62
58
  .is-warning { background-color: var(--n-color-warning); color: white; }
63
59
  .is-info { background-color: var(--n-color-info); color: white; }
64
-
65
60
  .n-avatar-initials {
66
61
  line-height: 1;
67
62
  font-weight: var(--n-weight-bold);
68
63
  }
64
+
69
65
  </style>
@@ -29,21 +29,16 @@ const props = defineProps({
29
29
  text-transform: uppercase;
30
30
  letter-spacing: 0.03em;
31
31
  transition: all var(--n-transition-fast);
32
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.2);
33
32
  }
34
-
35
33
  .n-badge-primary { background: var(--n-color-primary); color: white; }
36
34
  .n-badge-success { background: var(--n-color-success); color: white; }
37
35
  .n-badge-danger { background: var(--n-color-danger); color: white; }
38
36
  .n-badge-warning { background: var(--n-color-warning); color: white; }
39
37
  .n-badge-info { background: var(--n-color-info); color: white; }
40
38
  .n-badge-secondary { background: var(--n-color-surface-hover); color: var(--n-color-text); }
41
-
42
39
  .n-badge-sm { padding: 0.15rem 0.4rem; font-size: 0.65rem; }
43
40
  .n-badge-lg { padding: 0.4rem 0.8rem; font-size: var(--n-text-sm); }
44
-
45
41
  .is-rounded { border-radius: var(--n-radius-full); }
46
-
47
42
  .n-badge-dot {
48
43
  display: inline-block;
49
44
  width: 8px;
@@ -52,11 +47,11 @@ const props = defineProps({
52
47
  vertical-align: middle;
53
48
  flex-shrink: 0;
54
49
  }
55
-
56
50
  .n-badge-dot.is-primary { background: var(--n-color-primary); }
57
51
  .n-badge-dot.is-success { background: var(--n-color-success); }
58
52
  .n-badge-dot.is-danger { background: var(--n-color-danger); }
59
53
  .n-badge-dot.is-warning { background: var(--n-color-warning); }
60
54
  .n-badge-dot.is-info { background: var(--n-color-info); }
61
55
  .n-badge-dot.is-secondary { background: var(--n-color-text-muted); }
56
+
62
57
  </style>
@@ -98,11 +98,9 @@ const overlayOpacity = computed(() => {
98
98
  display: flex;
99
99
  align-items: flex-end;
100
100
  }
101
-
102
101
  .n-bottom-sheet-root.is-active {
103
102
  pointer-events: auto;
104
103
  }
105
-
106
104
  .n-bottom-sheet-overlay {
107
105
  position: absolute;
108
106
  top: 0;
@@ -113,7 +111,6 @@ const overlayOpacity = computed(() => {
113
111
  backdrop-filter: blur(8px);
114
112
  transition: opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1);
115
113
  }
116
-
117
114
  .n-bottom-sheet-container {
118
115
  position: relative;
119
116
  width: 100%;
@@ -128,7 +125,6 @@ const overlayOpacity = computed(() => {
128
125
  flex-direction: column;
129
126
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
130
127
  }
131
-
132
128
  .n-bottom-sheet-handle {
133
129
  width: 48px;
134
130
  height: 5px;
@@ -138,10 +134,10 @@ const overlayOpacity = computed(() => {
138
134
  flex-shrink: 0;
139
135
  opacity: 0.3;
140
136
  }
141
-
142
137
  .n-bottom-sheet-inner {
143
138
  padding: var(--n-space-4) var(--n-space-8) var(--n-space-8);
144
139
  overflow-y: auto;
145
140
  flex: 1;
146
141
  }
142
+
147
143
  </style>
@@ -1,320 +1,241 @@
1
- <script setup>
2
- import { signal, computed } from 'nexa-framework'
3
-
4
- const props = defineProps({
5
- variant: { type: String, default: 'primary' },
6
- size: { type: String, default: 'md' },
7
- type: { type: String, default: 'button' },
8
- disabled: { type: Boolean, default: false },
9
- loading: { type: Boolean, default: false },
10
- block: { type: Boolean, default: false },
11
- rounded: { type: Boolean, default: false },
12
- loadingText: { type: String, default: '' }
13
- })
14
-
15
- const emit = defineEmits(['click'])
16
-
17
- const ripple = signal([])
18
-
19
- const handleClick = (e) => {
20
- if (props.disabled || props.loading) return
21
- emit('click', e)
22
- const rect = e.currentTarget.getBoundingClientRect()
23
- const x = e.clientX - rect.left
24
- const y = e.clientY - rect.top
25
- const id = Date.now()
26
- ripple.value = [...ripple.value, { id, x, y }]
27
- setTimeout(() => {
28
- ripple.value = ripple.value.filter(r => r.id !== id)
29
- }, 600)
30
- }
31
-
32
- const btnClass = computed(() => {
33
- return [
34
- 'n-btn',
35
- `n-btn-${props.variant}`,
36
- `n-btn-${props.size}`,
37
- props.loading ? 'is-loading' : '',
38
- props.block ? 'is-block' : '',
39
- props.rounded ? 'is-rounded' : ''
40
- ].join(' ')
41
- })
42
- </script>
43
-
44
- <template>
45
- <button
46
- :class="btnClass.value"
47
- :type="type"
48
- :disabled="disabled || loading"
49
- :aria-busy="loading ? 'true' : undefined"
50
- @click="handleClick"
51
- >
52
- <span v-if="loading" class="n-btn-loader"></span>
53
- <span v-if="loading && loadingText" class="n-btn-loading-text">{{ loadingText }}</span>
54
- <span v-if="!loading || (loading && !loadingText)" class="n-btn-content">
55
- <slot />
56
- </span>
57
- <span v-for="r in ripple.value" :key="r.id" class="n-btn-ripple" :style="{ left: r.x + 'px', top: r.y + 'px' }"></span>
58
- </button>
59
- </template>
60
-
61
- <style scoped>
62
- .n-btn {
63
- position: relative;
64
- display: inline-flex;
65
- align-items: center;
66
- justify-content: center;
67
- gap: var(--n-space-2);
68
- font-family: var(--n-font-sans);
69
- font-weight: var(--n-weight-semibold);
70
- letter-spacing: 0.01em;
71
- border-radius: var(--n-radius-md);
72
- cursor: pointer;
73
- transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
74
- border: 1px solid transparent;
75
- outline: none;
76
- white-space: nowrap;
77
- user-select: none;
78
- overflow: hidden;
79
- text-decoration: none;
80
- line-height: var(--n-leading-normal, 1.5);
81
- min-width: fit-content;
82
- will-change: transform;
83
- -webkit-tap-highlight-color: transparent;
84
- }
85
-
86
- .n-btn:focus-visible {
87
- box-shadow: 0 0 0 3px var(--n-color-primary-light), 0 0 0 1px var(--n-color-primary);
88
- }
89
-
90
- /* Sizes */
91
- .n-btn-sm { padding: 0.5rem 1.5rem; font-size: var(--n-text-sm); gap: var(--n-space-1); border-radius: var(--n-radius-sm); min-height: 36px; }
92
- .n-btn-md { padding: 0.75rem 2rem; font-size: var(--n-text-base); min-height: 44px; }
93
- .n-btn-lg { padding: 1rem 2.75rem; font-size: var(--n-text-lg); border-radius: var(--n-radius-lg); min-height: 52px; }
94
-
95
- /* Block */
96
- .is-block { width: 100%; }
97
-
98
- /* Rounded */
99
- .is-rounded { border-radius: var(--n-radius-full); }
100
-
101
- /* Active/Press */
102
- .n-btn:active:not(:disabled) {
103
- transform: scale(0.97);
104
- }
105
-
106
- /* Variant: Primary */
107
- .n-btn-primary {
108
- background: linear-gradient(135deg, #6366f1 0%, #4f46e5 50%, #4338ca 100%);
109
- color: white;
110
- box-shadow: 0 4px 14px rgba(99, 102, 241, 0.4), 0 0 0 1px rgba(99, 102, 241, 0.3);
111
- text-shadow: 0 1px 2px rgba(0,0,0,0.2);
112
- }
113
- .n-btn-primary:hover:not(:disabled) {
114
- transform: translateY(-3px) scale(1.02);
115
- box-shadow: 0 8px 25px rgba(99, 102, 241, 0.5), 0 0 0 1px rgba(99, 102, 241, 0.4), 0 0 40px rgba(99, 102, 241, 0.15);
116
- }
117
- .n-btn-primary:active:not(:disabled) {
118
- transform: translateY(-1px) scale(0.98);
119
- box-shadow: 0 2px 8px rgba(99, 102, 241, 0.4), inset 0 2px 4px rgba(0,0,0,0.15);
120
- }
121
-
122
- /* Variant: Secondary */
123
- .n-btn-secondary {
124
- background: var(--n-color-surface-alt);
125
- color: var(--n-color-text);
126
- border-color: var(--n-color-border);
127
- }
128
- .n-btn-secondary:hover:not(:disabled) {
129
- background: var(--n-color-surface-hover);
130
- border-color: var(--n-color-border-hover);
131
- transform: translateY(-1px);
132
- }
133
- .n-btn-secondary:active:not(:disabled) {
134
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.08);
135
- }
136
-
137
- /* Variant: Success */
138
- .n-btn-success {
139
- background: linear-gradient(135deg, var(--n-color-success) 0%, var(--n-color-success-hover) 100%);
140
- color: white;
141
- box-shadow: var(--n-shadow-glow-success);
142
- }
143
- .n-btn-success:hover:not(:disabled) {
144
- transform: translateY(-2px);
145
- box-shadow: var(--n-shadow-glow-success);
146
- }
147
- .n-btn-success:active:not(:disabled) {
148
- box-shadow: var(--n-shadow-glow-success), inset 0 1px 3px rgba(0,0,0,0.15);
149
- }
150
-
151
- /* Variant: Warning */
152
- .n-btn-warning {
153
- background: linear-gradient(135deg, var(--n-color-warning) 0%, var(--n-color-warning-hover) 100%);
154
- color: white;
155
- box-shadow: var(--n-shadow-glow-warning);
156
- }
157
- .n-btn-warning:hover:not(:disabled) {
158
- transform: translateY(-2px);
159
- box-shadow: var(--n-shadow-glow-warning);
160
- }
161
- .n-btn-warning:active:not(:disabled) {
162
- box-shadow: var(--n-shadow-glow-warning), inset 0 1px 3px rgba(0,0,0,0.15);
163
- }
164
-
165
- /* Variant: Info */
166
- .n-btn-info {
167
- background: linear-gradient(135deg, var(--n-color-info) 0%, var(--n-color-info-hover) 100%);
168
- color: white;
169
- box-shadow: var(--n-shadow-glow-info);
170
- }
171
- .n-btn-info:hover:not(:disabled) {
172
- transform: translateY(-2px);
173
- box-shadow: var(--n-shadow-glow-info);
174
- }
175
- .n-btn-info:active:not(:disabled) {
176
- box-shadow: var(--n-shadow-glow-info), inset 0 1px 3px rgba(0,0,0,0.15);
177
- }
178
-
179
- /* Variant: Danger */
180
- .n-btn-danger {
181
- background: linear-gradient(135deg, var(--n-color-danger) 0%, var(--n-color-danger-hover) 100%);
182
- color: white;
183
- box-shadow: var(--n-shadow-glow-danger);
184
- }
185
- .n-btn-danger:hover:not(:disabled) {
186
- transform: translateY(-2px);
187
- box-shadow: var(--n-shadow-glow-danger);
188
- }
189
- .n-btn-danger:active:not(:disabled) {
190
- box-shadow: var(--n-shadow-glow-danger), inset 0 1px 3px rgba(0,0,0,0.15);
191
- }
192
-
193
- /* Variant: Ghost */
194
- .n-btn-ghost {
195
- background: transparent;
196
- backdrop-filter: blur(12px);
197
- -webkit-backdrop-filter: blur(12px);
198
- color: var(--n-color-text-secondary);
199
- border-color: transparent;
200
- }
201
- .n-btn-ghost:hover:not(:disabled) {
202
- background: var(--n-color-glass);
203
- backdrop-filter: blur(12px);
204
- -webkit-backdrop-filter: blur(12px);
205
- color: var(--n-color-text);
206
- border-color: var(--n-color-glass-border);
207
- }
208
- .n-btn-ghost:active:not(:disabled) {
209
- background: var(--n-color-glass-hover);
210
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.06);
211
- }
212
-
213
- /* Variant: Outline */
214
- .n-btn-outline {
215
- background: transparent;
216
- color: var(--n-color-primary);
217
- border: 1.5px solid transparent;
218
- background-image: linear-gradient(transparent, transparent), linear-gradient(135deg, var(--n-color-primary), var(--n-color-primary-hover));
219
- background-origin: padding-box, border-box;
220
- background-clip: padding-box, border-box;
221
- }
222
- .n-btn-outline:hover:not(:disabled) {
223
- background-image: linear-gradient(var(--n-color-primary-light), var(--n-color-primary-light)), linear-gradient(135deg, var(--n-color-primary-hover), var(--n-color-primary));
224
- background-origin: padding-box, border-box;
225
- background-clip: padding-box, border-box;
226
- color: var(--n-color-primary-hover);
227
- }
228
- .n-btn-outline:active:not(:disabled) {
229
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.08);
230
- }
231
-
232
- /* Variant: Glass */
233
- .n-btn-glass {
234
- background: var(--n-color-glass);
235
- backdrop-filter: blur(10px);
236
- border-color: var(--n-color-glass-border);
237
- color: var(--n-color-text);
238
- }
239
- .n-btn-glass:hover:not(:disabled) {
240
- background: var(--n-color-glass-hover);
241
- border-color: var(--n-color-border-hover);
242
- }
243
- .n-btn-glass:active:not(:disabled) {
244
- box-shadow: inset 0 1px 3px rgba(0,0,0,0.08);
245
- }
246
-
247
- /* Disabled */
248
- .n-btn:disabled {
249
- cursor: not-allowed;
250
- transform: none !important;
251
- box-shadow: none !important;
252
- pointer-events: none;
253
- opacity: 0.55;
254
- }
255
- .n-btn:disabled::after {
256
- content: '';
257
- position: absolute;
258
- inset: 0;
259
- border-radius: inherit;
260
- background: var(--n-color-surface, #fff);
261
- opacity: 0.3;
262
- pointer-events: none;
263
- }
264
-
265
- /* Loader */
266
- .n-btn-loader {
267
- width: 1rem;
268
- height: 1rem;
269
- border: 2px solid currentColor;
270
- border-right-color: transparent;
271
- border-radius: var(--n-radius-full);
272
- animation: n-spin 0.7s linear infinite;
273
- flex-shrink: 0;
274
- }
275
-
276
- .n-btn-lg .n-btn-loader {
277
- width: 1.25rem;
278
- height: 1.25rem;
279
- border-width: 2.5px;
280
- }
281
-
282
- .n-btn-sm .n-btn-loader {
283
- width: 0.85rem;
284
- height: 0.85rem;
285
- }
286
-
287
- .n-btn-loading-text {
288
- opacity: 0.8;
289
- font-weight: var(--n-weight-normal);
290
- }
291
-
292
- .n-btn-content {
293
- display: inline-flex;
294
- align-items: center;
295
- gap: var(--n-space-2);
296
- }
297
-
298
- @keyframes n-spin {
299
- from { transform: rotate(0deg); }
300
- to { transform: rotate(360deg); }
301
- }
302
-
303
- /* Ripple */
304
- .n-btn-ripple {
305
- position: absolute;
306
- border-radius: var(--n-radius-full);
307
- background: var(--n-color-glass);
308
- width: 20px;
309
- height: 20px;
310
- margin-left: -10px;
311
- margin-top: -10px;
312
- pointer-events: none;
313
- animation: n-ripple 0.6s ease-out forwards;
314
- }
315
-
316
- @keyframes n-ripple {
317
- from { transform: scale(0); opacity: 1; }
318
- to { transform: scale(8); opacity: 0; }
319
- }
320
- </style>
1
+ <script setup>
2
+ import { signal, computed } from 'nexa-framework'
3
+
4
+ const props = defineProps({
5
+ label: { type: String, default: '' },
6
+ variant: { type: String, default: 'primary' },
7
+ size: { type: String, default: 'md' },
8
+ disabled: { type: Boolean, default: false },
9
+ loading: { type: Boolean, default: false },
10
+ icon: { type: String, default: '' },
11
+ iconRight: { type: String, default: '' },
12
+ block: { type: Boolean, default: false },
13
+ rounded: { type: Boolean, default: false },
14
+ outlined: { type: Boolean, default: false }
15
+ })
16
+
17
+ const emit = defineEmits(['click'])
18
+
19
+ const isPressed = signal(false)
20
+
21
+ const handleClick = (e) => {
22
+ if (props.disabled || props.loading) return
23
+ isPressed.value = true
24
+ setTimeout(() => { isPressed.value = false }, 150)
25
+ emit('click', e)
26
+ }
27
+ </script>
28
+
29
+ <template>
30
+ <button
31
+ class="n-btn"
32
+ :class="[
33
+ `n-btn-${variant}`,
34
+ `n-btn-${size}`,
35
+ { 'is-block': block, 'is-rounded': rounded, 'is-outlined': outlined, 'is-pressed': isPressed }
36
+ ]"
37
+ :disabled="disabled || loading"
38
+ @click="handleClick"
39
+ >
40
+ <span v-if="loading" class="n-btn-spinner"></span>
41
+ <span v-if="icon && !loading" class="n-btn-icon">{{ icon }}</span>
42
+ <span v-if="label" class="n-btn-label">{{ label }}</span>
43
+ <span v-if="iconRight" class="n-btn-icon-right">{{ iconRight }}</span>
44
+ <slot />
45
+ </button>
46
+ </template>
47
+
48
+ <style scoped>
49
+ .n-btn {
50
+ display: inline-flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ gap: 0.5rem;
54
+ font-family: inherit;
55
+ font-weight: 500;
56
+ border: 1px solid transparent;
57
+ cursor: pointer;
58
+ transition: background-color var(--n-transition-fast), border-color var(--n-transition-fast), color var(--n-transition-fast), box-shadow var(--n-transition-fast);
59
+ position: relative;
60
+ overflow: hidden;
61
+ user-select: none;
62
+ }
63
+ .n-btn:disabled {
64
+ opacity: 0.6;
65
+ cursor: not-allowed;
66
+ }
67
+ .n-btn:focus-visible {
68
+ outline: none;
69
+ }
70
+
71
+ /* Sizes */
72
+ .n-btn-sm {
73
+ padding: 0.375rem 0.75rem;
74
+ font-size: var(--n-text-sm);
75
+ border-radius: var(--n-radius-md);
76
+ min-height: 32px;
77
+ }
78
+ .n-btn-md {
79
+ padding: 0.5rem 1rem;
80
+ font-size: var(--n-text-base);
81
+ border-radius: var(--n-radius-md);
82
+ min-height: 40px;
83
+ }
84
+ .n-btn-lg {
85
+ padding: 0.75rem 1.5rem;
86
+ font-size: var(--n-text-lg);
87
+ border-radius: var(--n-radius-lg);
88
+ min-height: 48px;
89
+ }
90
+
91
+ /* Block & Rounded */
92
+ .is-block { width: 100%; }
93
+ .is-rounded { border-radius: var(--n-radius-full); }
94
+
95
+ /* Primary */
96
+ .n-btn-primary {
97
+ background-color: var(--n-color-primary);
98
+ color: var(--n-color-primary-text);
99
+ border-color: var(--n-color-primary);
100
+ }
101
+ .n-btn-primary:hover:not(:disabled) {
102
+ background-color: var(--n-color-primary-hover);
103
+ border-color: var(--n-color-primary-hover);
104
+ }
105
+ .n-btn-primary:active:not(:disabled), .is-pressed.n-btn-primary {
106
+ background-color: var(--n-color-primary-active);
107
+ border-color: var(--n-color-primary-active);
108
+ }
109
+ .n-btn-primary:focus-visible {
110
+ box-shadow: var(--n-ring-primary);
111
+ }
112
+
113
+ /* Secondary */
114
+ .n-btn-secondary {
115
+ background-color: var(--n-color-surface-alt);
116
+ color: var(--n-color-text);
117
+ border-color: var(--n-color-border);
118
+ }
119
+ .n-btn-secondary:hover:not(:disabled) {
120
+ background-color: var(--n-color-surface-hover);
121
+ border-color: var(--n-color-border-hover);
122
+ }
123
+ .n-btn-secondary:active:not(:disabled), .is-pressed.n-btn-secondary {
124
+ background-color: var(--n-color-border);
125
+ }
126
+ .n-btn-secondary:focus-visible {
127
+ box-shadow: var(--n-ring-surface);
128
+ }
129
+
130
+ /* Success */
131
+ .n-btn-success {
132
+ background-color: var(--n-color-success);
133
+ color: #fff;
134
+ border-color: var(--n-color-success);
135
+ }
136
+ .n-btn-success:hover:not(:disabled) {
137
+ background-color: var(--n-color-success-hover);
138
+ border-color: var(--n-color-success-hover);
139
+ }
140
+ .n-btn-success:active:not(:disabled), .is-pressed.n-btn-success {
141
+ background-color: var(--n-color-success-active);
142
+ }
143
+ .n-btn-success:focus-visible { box-shadow: var(--n-ring-success); }
144
+
145
+ /* Danger */
146
+ .n-btn-danger {
147
+ background-color: var(--n-color-danger);
148
+ color: #fff;
149
+ border-color: var(--n-color-danger);
150
+ }
151
+ .n-btn-danger:hover:not(:disabled) {
152
+ background-color: var(--n-color-danger-hover);
153
+ border-color: var(--n-color-danger-hover);
154
+ }
155
+ .n-btn-danger:active:not(:disabled), .is-pressed.n-btn-danger {
156
+ background-color: var(--n-color-danger-active);
157
+ }
158
+ .n-btn-danger:focus-visible { box-shadow: var(--n-ring-danger); }
159
+
160
+ /* Warning */
161
+ .n-btn-warning {
162
+ background-color: var(--n-color-warning);
163
+ color: #fff;
164
+ border-color: var(--n-color-warning);
165
+ }
166
+ .n-btn-warning:hover:not(:disabled) {
167
+ background-color: var(--n-color-warning-hover);
168
+ border-color: var(--n-color-warning-hover);
169
+ }
170
+ .n-btn-warning:active:not(:disabled), .is-pressed.n-btn-warning {
171
+ background-color: var(--n-color-warning-active);
172
+ }
173
+ .n-btn-warning:focus-visible { box-shadow: var(--n-ring-warning); }
174
+
175
+ /* Info */
176
+ .n-btn-info {
177
+ background-color: var(--n-color-info);
178
+ color: #fff;
179
+ border-color: var(--n-color-info);
180
+ }
181
+ .n-btn-info:hover:not(:disabled) {
182
+ background-color: var(--n-color-info-hover);
183
+ border-color: var(--n-color-info-hover);
184
+ }
185
+ .n-btn-info:active:not(:disabled), .is-pressed.n-btn-info {
186
+ background-color: var(--n-color-info-active);
187
+ }
188
+ .n-btn-info:focus-visible { box-shadow: var(--n-ring-info); }
189
+
190
+ /* Ghost */
191
+ .n-btn-ghost {
192
+ background-color: transparent;
193
+ color: var(--n-color-text);
194
+ border-color: transparent;
195
+ }
196
+ .n-btn-ghost:hover:not(:disabled) {
197
+ background-color: var(--n-color-surface-hover);
198
+ color: var(--n-color-text);
199
+ }
200
+ .n-btn-ghost:active:not(:disabled), .is-pressed.n-btn-ghost {
201
+ background-color: var(--n-color-border);
202
+ }
203
+ .n-btn-ghost:focus-visible {
204
+ box-shadow: var(--n-ring-surface);
205
+ }
206
+
207
+ /* Outlined variants */
208
+ .is-outlined {
209
+ background-color: transparent !important;
210
+ }
211
+ .is-outlined.n-btn-primary { color: var(--n-color-primary); }
212
+ .is-outlined.n-btn-primary:hover:not(:disabled) { background-color: var(--n-color-primary-light) !important; }
213
+
214
+ .is-outlined.n-btn-success { color: var(--n-color-success); border-color: var(--n-color-success); }
215
+ .is-outlined.n-btn-success:hover:not(:disabled) { background-color: rgba(34, 197, 94, 0.1) !important; }
216
+
217
+ .is-outlined.n-btn-danger { color: var(--n-color-danger); border-color: var(--n-color-danger); }
218
+ .is-outlined.n-btn-danger:hover:not(:disabled) { background-color: rgba(239, 68, 68, 0.1) !important; }
219
+
220
+ /* Spinner */
221
+ .n-btn-spinner {
222
+ width: 16px;
223
+ height: 16px;
224
+ border: 2px solid currentColor;
225
+ border-right-color: transparent;
226
+ border-radius: 50%;
227
+ animation: n-spin 0.6s linear infinite;
228
+ }
229
+ @keyframes n-spin {
230
+ to { transform: rotate(360deg); }
231
+ }
232
+
233
+ .n-btn-icon, .n-btn-icon-right {
234
+ display: flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ }
238
+ .n-btn-label {
239
+ line-height: 1;
240
+ }
241
+ </style>