nexa-ui-kit 0.11.5 → 0.11.8

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 +202 -294
  12. package/dist/components/NButton.nexa +224 -318
  13. package/dist/components/NCard.js +39 -82
  14. package/dist/components/NCard.nexa +27 -71
  15. package/dist/components/NCheckbox.js +77 -60
  16. package/dist/components/NCheckbox.nexa +71 -45
  17. package/dist/components/NChips.nexa +1 -0
  18. package/dist/components/NDataTable.js +1 -313
  19. package/dist/components/NDataTable.nexa +2 -314
  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 +4 -4
  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 +224 -318
  69. package/src/components/NCard.nexa +27 -71
  70. package/src/components/NCheckbox.nexa +71 -45
  71. package/src/components/NChips.nexa +1 -0
  72. package/src/components/NDataTable.nexa +2 -314
  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
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { signal, computed, inject, effect } from 'nexa-framework'
2
+ import { signal, computed } from 'nexa-framework'
3
3
 
4
4
  const props = defineProps({
5
5
  modelValue: { type: [String, Number], default: '' },
@@ -7,327 +7,157 @@ const props = defineProps({
7
7
  placeholder: { type: String, default: '' },
8
8
  label: { type: String, default: '' },
9
9
  error: { type: String, default: '' },
10
- id: { type: String, default: '' },
11
- name: { type: String, default: '' },
12
- autocomplete: { type: String, default: '' },
13
- ariaDescribedby: { type: String, default: '' },
14
- ariaInvalid: { type: [Boolean, String], default: false },
15
- bindField: { type: Boolean, default: false },
16
10
  disabled: { type: Boolean, default: false },
17
11
  readonly: { type: Boolean, default: false },
12
+ required: { type: Boolean, default: false },
18
13
  clearable: { type: Boolean, default: false },
19
- maxlength: { type: Number, default: 0 },
20
- prefixIcon: { type: String, default: '' },
21
- suffixIcon: { type: String, default: '' }
14
+ prefix: { type: String, default: '' },
15
+ suffix: { type: String, default: '' }
22
16
  })
23
17
 
24
- const emit = defineEmits(['update:modelValue', 'clear', 'focus', 'blur'])
18
+ const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'clear'])
25
19
 
26
- const field = inject('nexa-ui:form-field', undefined)
27
-
28
- const showPassword = signal(false)
29
20
  const isFocused = signal(false)
30
21
 
31
- const effectiveValue = computed(() => {
32
- if (props.bindField && field?.value) return field.value.value
33
- return props.modelValue
34
- })
35
-
36
- const draft = signal(String(effectiveValue.value ?? ''))
37
-
38
- effect(() => {
39
- const next = String(effectiveValue.value ?? '')
40
- if (draft.value === next) return
41
- draft.value = next
42
- })
43
-
44
- const effectiveId = computed(() => {
45
- if (props.id) return props.id
46
- if (props.bindField && field?.inputId) return field.inputId.value
47
- return ''
48
- })
49
-
50
- const effectiveDescribedBy = computed(() => {
51
- if (props.ariaDescribedby) return props.ariaDescribedby
52
- if (props.bindField && field?.describedBy) return field.describedBy.value || ''
53
- return ''
54
- })
55
-
56
- const effectiveInvalid = computed(() => {
57
- if (props.bindField && field?.invalid) return field.invalid.value
58
- return props.ariaInvalid
59
- })
60
-
61
- const effectiveError = computed(() => {
62
- if (props.error) return props.error
63
- if (props.bindField && field?.error) return field.error.value || ''
64
- return ''
65
- })
66
-
67
- const effectiveDisabled = computed(() => {
68
- if (props.disabled) return true
69
- if (props.bindField && field?.disabled) return !!field.disabled.value
70
- return false
71
- })
72
-
73
- const inputType = computed(() => {
74
- if (props.type === 'password' && showPassword.value) return 'text'
75
- return props.type
76
- })
77
-
78
- const currentLength = computed(() => draft.value.length)
79
-
80
- const onInput = (e) => {
81
- const next = e.target.value
82
- if (draft.value !== next) draft.value = next
83
- if (props.bindField && field?.setValue) {
84
- field.setValue(next)
85
- return
86
- }
87
- emit('update:modelValue', next)
22
+ const handleInput = (e) => {
23
+ emit('update:modelValue', e.target.value)
88
24
  }
89
25
 
90
- const onFocus = () => {
26
+ const handleFocus = (e) => {
91
27
  isFocused.value = true
92
- emit('focus')
28
+ emit('focus', e)
93
29
  }
94
30
 
95
- const onBlur = () => {
31
+ const handleBlur = (e) => {
96
32
  isFocused.value = false
97
- if (props.bindField && field?.onBlur) {
98
- field.onBlur()
99
- }
100
- emit('blur')
33
+ emit('blur', e)
101
34
  }
102
35
 
103
- const clear = () => {
104
- if (draft.value) draft.value = ''
105
- if (props.bindField && field?.setValue) {
106
- field.setValue('')
107
- emit('clear')
108
- return
109
- }
36
+ const handleClear = () => {
110
37
  emit('update:modelValue', '')
111
38
  emit('clear')
112
39
  }
113
-
114
- const togglePassword = () => {
115
- showPassword.value = !showPassword.value
116
- }
117
40
  </script>
118
41
 
119
42
  <template>
120
- <div class="n-input-group">
121
- <label v-if="label" class="n-input-label">{{ label }}</label>
122
- <div class="n-input-wrapper" :class="{ 'is-focused': isFocused.value, 'has-error': effectiveError.value, 'is-disabled': effectiveDisabled.value }">
123
- <span v-if="prefixIcon" class="n-input-icon is-prefix">{{ prefixIcon }}</span>
43
+ <div class="n-input-wrapper" :class="{ 'is-focused': isFocused, 'is-error': error, 'is-disabled': disabled }">
44
+ <label v-if="label" class="n-input-label">
45
+ {{ label }}
46
+ <span v-if="required" class="n-input-required">*</span>
47
+ </label>
48
+ <div class="n-input-container">
49
+ <span v-if="prefix" class="n-input-prefix">{{ prefix }}</span>
124
50
  <input
125
- :id="effectiveId.value || undefined"
126
- :name="name || undefined"
127
- :type="inputType.value"
128
- :value="draft.value"
51
+ :type="type"
52
+ :value="modelValue"
129
53
  :placeholder="placeholder"
130
- :disabled="effectiveDisabled.value"
54
+ :disabled="disabled"
131
55
  :readonly="readonly"
132
- :autocomplete="autocomplete || undefined"
133
- :aria-describedby="effectiveDescribedBy.value || undefined"
134
- :aria-invalid="effectiveInvalid.value || undefined"
135
- :maxlength="maxlength || undefined"
56
+ :required="required"
136
57
  class="n-input"
137
- :class="{ 'has-prefix': !!prefixIcon, 'has-suffix': !!suffixIcon || clearable || type === 'password' }"
138
- @input="onInput"
139
- @focus="onFocus"
140
- @blur="onBlur"
58
+ @input="handleInput"
59
+ @focus="handleFocus"
60
+ @blur="handleBlur"
141
61
  />
142
- <div class="n-input-focus-ring"></div>
143
- <div class="n-input-actions">
144
- <button v-if="clearable && draft.value" class="n-input-action" @click="clear" tabindex="-1" type="button" aria-label="Clear"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M18 6L6 18"/><path d="M6 6l12 12"/></svg></button>
145
- <button v-if="type === 'password'" class="n-input-action" @click="togglePassword" tabindex="-1" type="button" :aria-label="showPassword.value ? 'Hide password' : 'Show password'">
146
- <svg v-if="!showPassword.value" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
147
- <svg v-else viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/><path d="M23 1L1 23"/></svg>
148
- </button>
149
- <span v-if="suffixIcon" class="n-input-icon is-suffix">{{ suffixIcon }}</span>
150
- </div>
151
- </div>
152
- <div class="n-input-bottom">
153
- <span v-if="effectiveError.value" class="n-input-error-msg">{{ effectiveError.value }}</span>
154
- <span v-if="maxlength > 0" class="n-input-counter">{{ currentLength.value }}/{{ maxlength }}</span>
62
+ <button v-if="clearable && modelValue" class="n-input-clear" @click="handleClear" type="button">
63
+ <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
64
+ <line x1="18" y1="6" x2="6" y2="18"/>
65
+ <line x1="6" y1="6" x2="18" y2="18"/>
66
+ </svg>
67
+ </button>
68
+ <span v-if="suffix" class="n-input-suffix">{{ suffix }}</span>
155
69
  </div>
70
+ <span v-if="error" class="n-input-error">{{ error }}</span>
156
71
  </div>
157
72
  </template>
158
73
 
159
74
  <style scoped>
160
- .n-input-group {
75
+ .n-input-wrapper {
161
76
  display: flex;
162
77
  flex-direction: column;
163
- gap: var(--n-space-2);
78
+ gap: 0.5rem;
164
79
  width: 100%;
165
80
  }
166
-
167
81
  .n-input-label {
168
- font-size: var(--n-text-sm);
169
- font-weight: var(--n-weight-medium);
170
- color: var(--n-color-text-secondary);
171
- margin-left: var(--n-space-1);
172
- letter-spacing: 0.01em;
82
+ font-size: 0.875rem;
83
+ font-weight: 500;
84
+ color: var(--n-color-text);
85
+ letter-spacing: normal;
173
86
  }
174
-
175
- .n-input-wrapper {
87
+ .n-input-required {
88
+ color: var(--n-color-danger);
89
+ margin-left: 0.25rem;
90
+ }
91
+ .n-input-container {
176
92
  position: relative;
177
93
  display: flex;
178
94
  align-items: center;
179
- transition: all var(--n-transition-fast);
180
- }
181
-
182
- .n-input {
183
- position: relative;
184
- z-index: 1;
185
- width: 100%;
186
- min-height: 44px;
187
- background: var(--n-color-bg);
95
+ background-color: var(--n-color-surface);
188
96
  border: 1px solid var(--n-color-border);
189
- color: var(--n-color-text);
190
- padding: 0.75rem 1.125rem;
191
97
  border-radius: var(--n-radius-md);
192
- font-family: inherit;
193
- font-size: var(--n-text-base);
194
- line-height: 1.2;
195
- box-sizing: border-box;
196
- transition: all var(--n-transition-normal) cubic-bezier(0.16, 1, 0.3, 1);
197
- outline: none;
198
- caret-color: var(--n-color-primary);
199
- -webkit-font-smoothing: antialiased;
200
- -moz-osx-font-smoothing: grayscale;
201
- }
202
-
203
- .n-input.has-prefix {
204
- padding-left: 2.5rem;
205
- }
206
-
207
- .n-input.has-suffix {
208
- padding-right: 2.5rem;
209
- }
210
-
211
- .n-input::placeholder {
212
- color: var(--n-color-text-muted);
98
+ transition: background-color var(--n-transition-fast), border-color var(--n-transition-fast), color var(--n-transition-fast), box-shadow var(--n-transition-fast);
213
99
  }
214
-
215
- .n-input-focus-ring {
216
- position: absolute;
217
- inset: 0;
218
- border-radius: var(--n-radius-md);
219
- background: linear-gradient(135deg, var(--n-color-primary), var(--n-color-info));
220
- opacity: 0;
221
- pointer-events: none;
222
- transition: opacity var(--n-transition-normal) cubic-bezier(0.16, 1, 0.3, 1);
223
- z-index: 0;
100
+ .n-input-container:hover {
101
+ border-color: var(--n-color-border-hover);
224
102
  }
225
-
226
- .is-focused .n-input-focus-ring {
227
- opacity: 0.15;
228
- }
229
-
230
- .is-focused .n-input {
103
+ .is-focused .n-input-container {
231
104
  border-color: var(--n-color-primary);
232
- background: var(--n-color-surface);
233
- box-shadow:
234
- 0 0 0 3px var(--n-color-primary-light),
235
- 0 0 0 1px var(--n-color-primary),
236
- inset 0 1px 3px rgba(0,0,0,0.04);
105
+ box-shadow: var(--n-ring-primary);
237
106
  }
238
-
239
- .has-error .n-input {
107
+ .is-error .n-input-container {
240
108
  border-color: var(--n-color-danger);
241
109
  }
242
-
243
- .has-error .n-input-focus-ring {
244
- background: var(--n-color-danger);
245
- opacity: 0.35;
110
+ .is-error.is-focused .n-input-container {
111
+ box-shadow: var(--n-ring-danger);
246
112
  }
247
-
248
- .n-input-icon {
249
- position: absolute;
250
- top: 50%;
251
- transform: translateY(-50%);
252
- color: var(--n-color-text-muted);
253
- font-size: var(--n-text-sm);
254
- pointer-events: none;
255
- display: flex;
256
- align-items: center;
257
- line-height: 1;
113
+ .is-disabled .n-input-container {
114
+ opacity: 0.6;
115
+ cursor: not-allowed;
116
+ background-color: var(--n-color-surface-alt);
258
117
  }
259
-
260
- .n-input-icon.is-prefix {
261
- left: 0.85rem;
118
+ .n-input {
119
+ flex: 1;
120
+ background: transparent;
121
+ border: none;
122
+ outline: none;
123
+ padding: 0.5rem 0.75rem;
124
+ font-size: 0.875rem;
125
+ color: var(--n-color-text);
126
+ font-family: inherit;
127
+ width: 100%;
262
128
  }
263
-
264
- .n-input-icon.is-suffix {
265
- right: 0.85rem;
129
+ .n-input::placeholder {
130
+ color: var(--n-color-text-muted);
266
131
  }
267
-
268
- .n-input-actions {
269
- position: absolute;
270
- right: 0.5rem;
271
- top: 50%;
272
- transform: translateY(-50%);
273
- display: flex;
274
- align-items: center;
275
- gap: 0.15rem;
132
+ .n-input:disabled {
133
+ cursor: not-allowed;
276
134
  }
277
-
278
- .n-input-action {
135
+ .n-input-prefix,
136
+ .n-input-suffix {
137
+ padding: 0 0.75rem;
138
+ color: var(--n-color-text-muted);
139
+ font-size: 0.875rem;
140
+ user-select: none;
141
+ }
142
+ .n-input-clear {
279
143
  background: transparent;
280
144
  border: none;
281
- color: var(--n-color-text-muted);
282
145
  cursor: pointer;
283
- padding: 0.25rem;
284
- font-size: var(--n-text-sm);
285
- border-radius: var(--n-radius-sm);
286
- transition: all var(--n-transition-fast);
146
+ padding: 0.5rem;
147
+ color: var(--n-color-text-muted);
148
+ transition: color var(--n-transition-fast);
287
149
  display: flex;
288
150
  align-items: center;
289
- line-height: 1;
151
+ justify-content: center;
290
152
  }
291
-
292
- .n-input-action:hover {
153
+ .n-input-clear:hover {
293
154
  color: var(--n-color-text);
294
- background: var(--n-color-glass);
295
155
  }
296
-
297
- .n-input-bottom {
156
+ .n-input-error {
157
+ font-size: 0.75rem;
158
+ color: var(--n-color-danger);
298
159
  display: flex;
299
- justify-content: space-between;
300
160
  align-items: center;
301
- padding: 0 var(--n-space-1);
302
- }
303
-
304
- .n-input-error-msg {
305
- font-size: var(--n-text-xs);
306
- color: var(--n-color-danger);
307
- }
308
-
309
- .n-input-counter {
310
- font-size: var(--n-text-xs);
311
- color: var(--n-color-text-muted);
312
- margin-left: auto;
313
- }
314
-
315
- .is-disabled {
316
- position: relative;
317
- }
318
-
319
- .is-disabled::after {
320
- content: '';
321
- position: absolute;
322
- inset: 0;
323
- background: var(--n-color-glass);
324
- border-radius: var(--n-radius-md);
325
- pointer-events: none;
326
- z-index: 2;
327
- }
328
-
329
- .is-disabled .n-input {
330
- cursor: not-allowed;
331
- background: var(--n-color-surface-alt);
161
+ gap: 0.25rem;
332
162
  }
333
163
  </style>
@@ -227,6 +227,6 @@ const onFocus = () => {
227
227
  </div>
228
228
  </template>
229
229
 
230
- <style scoped>
230
+ <style scoped>
231
231
  .n-inum{display:flex;flex-direction:column;gap:var(--n-space-2);width:100%;font-family:var(--n-font-sans)}.n-inum-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-inum-wrap{display:flex;align-items:stretch;min-height:44px;background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);overflow:hidden;transition:all var(--n-transition-fast)}.n-inum-wrap:focus-within{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-inum-input{flex:1;background:transparent;border:none;outline:none;padding:0.75rem 0.75rem;color:var(--n-color-text);font-size:var(--n-text-base);font-family:inherit;text-align:center;line-height:1.2;box-sizing:border-box}.n-inum-btn{width:2.5rem;background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:var(--n-text-base);transition:all var(--n-transition-fast)}.n-inum-btn:hover:not(:disabled){background:var(--n-color-glass);color:var(--n-color-text)}.n-inum-btn:disabled{opacity:0.5;cursor:not-allowed}.is-disabled{opacity:0.6;cursor:not-allowed;background:var(--n-color-surface-alt)}
232
232
  </style>
@@ -117,123 +117,6 @@ onUnmounted(() => {
117
117
  </Teleport>
118
118
  </template>
119
119
 
120
- <style scoped>
121
- .n-modal-root {
122
- position: fixed;
123
- top: 0;
124
- left: 0;
125
- width: 100vw;
126
- height: 100vh;
127
- display: flex;
128
- align-items: center;
129
- justify-content: center;
130
- z-index: var(--n-z-modal);
131
- }
132
-
133
- .n-modal-overlay {
134
- position: absolute;
135
- top: 0;
136
- left: 0;
137
- width: 100%;
138
- height: 100%;
139
- background: var(--n-color-overlay);
140
- backdrop-filter: blur(8px);
141
- opacity: 0;
142
- transition: opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1);
143
- }
144
-
145
- .n-modal-overlay.is-active {
146
- opacity: 1;
147
- }
148
-
149
- .n-modal-container {
150
- position: relative;
151
- width: 90%;
152
- background: var(--n-color-surface);
153
- backdrop-filter: blur(20px);
154
- -webkit-backdrop-filter: blur(20px);
155
- border: 1px solid var(--n-color-glass-border);
156
- border-radius: var(--n-radius-2xl);
157
- box-shadow: var(--n-shadow-xl), var(--n-shadow-glow-primary), 0 0 0 1px var(--n-color-glass-border);
158
- transform: scale(0.9) translateY(20px);
159
- opacity: 0;
160
- transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
161
- overflow: hidden;
162
- outline: none;
163
- max-height: 85vh;
164
- display: flex;
165
- flex-direction: column;
166
- }
167
-
168
- .n-modal-container.is-active {
169
- transform: scale(1) translateY(0);
170
- opacity: 1;
171
- }
172
-
173
- .n-modal-header {
174
- padding: var(--n-space-6) var(--n-space-8);
175
- border-bottom: 1px solid var(--n-color-border);
176
- display: flex;
177
- justify-content: space-between;
178
- align-items: center;
179
- flex-shrink: 0;
180
- }
181
-
182
- .n-modal-header h3 {
183
- margin: 0;
184
- font-size: var(--n-text-xl);
185
- font-weight: var(--n-weight-bold);
186
- color: var(--n-color-text);
187
- }
188
-
189
- .n-modal-close {
190
- background: transparent;
191
- border: none;
192
- color: var(--n-color-text-secondary);
193
- font-size: 1.75rem;
194
- cursor: pointer;
195
- transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
196
- padding: 0;
197
- line-height: 1;
198
- width: 44px;
199
- height: 44px;
200
- display: flex;
201
- align-items: center;
202
- justify-content: center;
203
- border-radius: var(--n-radius-lg);
204
- flex-shrink: 0;
205
- }
206
-
207
- .n-modal-close:hover {
208
- color: var(--n-color-text);
209
- background: var(--n-color-glass-hover);
210
- transform: scale(1.1);
211
- }
212
-
213
- .n-modal-close:active {
214
- transform: scale(0.95);
215
- }
216
-
217
- .n-modal-close:focus-visible {
218
- outline: 2px solid var(--n-color-primary);
219
- outline-offset: 2px;
220
- }
221
-
222
- .n-modal-content {
223
- padding: var(--n-space-8);
224
- color: var(--n-color-text-secondary);
225
- overflow-y: auto;
226
- overflow-x: hidden;
227
- flex: 1;
228
- }
229
-
230
- .n-modal-footer {
231
- padding: var(--n-space-5) var(--n-space-8);
232
- background: var(--n-color-glass);
233
- border-top: 1px solid var(--n-color-border);
234
- display: flex;
235
- justify-content: flex-end;
236
- gap: var(--n-space-4);
237
- flex-shrink: 0;
238
- }
120
+ <style scoped>
121
+ .n-modal-root {
239
122
  position: fixed;
240
123
  top: 0;
241
124
  left: 0;
242
125
  width: 100vw;
243
126
  height: 100vh;
244
127
  display: flex;
245
128
  align-items: center;
246
129
  justify-content: center;
247
130
  z-index: var(--n-z-modal);
248
131
  position: absolute;
249
132
  top: 0;
250
133
  left: 0;
251
134
  width: 100%;
252
135
  height: 100%;
253
136
  background: var(--n-color-overlay);
254
137
  backdrop-filter: blur(8px);
255
138
  opacity: 0;
256
139
  transition: opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1);
257
140
  opacity: 1;
258
141
  position: relative;
259
142
  width: 90%;
260
143
  background: var(--n-color-surface);
261
144
  backdrop-filter: blur(20px);
262
145
  -webkit-backdrop-filter: blur(20px);
263
146
  border: 1px solid var(--n-color-glass-border);
264
147
  border-radius: var(--n-radius-2xl);
265
148
  box-shadow: var(--n-shadow-xl), var(--n-shadow-glow-primary), 0 0 0 1px var(--n-color-glass-border);
266
149
  transform: scale(0.9) translateY(20px);
267
150
  opacity: 0;
268
151
  transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
269
152
  overflow: hidden;
270
153
  outline: none;
271
154
  max-height: 85vh;
272
155
  display: flex;
273
156
  flex-direction: column;
274
157
  transform: scale(1) translateY(0);
275
158
  opacity: 1;
276
159
  padding: var(--n-space-6) var(--n-space-8);
277
160
  border-bottom: 1px solid var(--n-color-border);
278
161
  display: flex;
279
162
  justify-content: space-between;
280
163
  align-items: center;
281
164
  flex-shrink: 0;
282
165
  margin: 0;
283
166
  font-size: var(--n-text-xl);
284
167
  font-weight: var(--n-weight-bold);
285
168
  color: var(--n-color-text);
286
169
  background: transparent;
287
170
  border: none;
288
171
  color: var(--n-color-text-secondary);
289
172
  font-size: 1.75rem;
290
173
  cursor: pointer;
291
174
  transition: color var(--n-transition-fast); cubic-bezier(0.34, 1.56, 0.64, 1);
292
175
  padding: 0;
293
176
  line-height: 1;
294
177
  width: 44px;
295
178
  height: 44px;
296
179
  display: flex;
297
180
  align-items: center;
298
181
  justify-content: center;
299
182
  border-radius: var(--n-radius-lg);
300
183
  flex-shrink: 0;
301
184
  color: var(--n-color-text);
302
185
  background: var(--n-color-glass-hover);
303
186
  transform: scale(0.95);
304
187
  outline: 2px solid var(--n-color-primary);
305
188
  outline-offset: 2px;
306
189
  padding: var(--n-space-8);
307
190
  color: var(--n-color-text-secondary);
308
191
  overflow-y: auto;
309
192
  overflow-x: hidden;
310
193
  flex: 1;
311
194
  padding: var(--n-space-5) var(--n-space-8);
312
195
  background: var(--n-color-glass);
313
196
  border-top: 1px solid var(--n-color-border);
314
197
  display: flex;
315
198
  justify-content: flex-end;
316
199
  gap: var(--n-space-4);
317
200
  flex-shrink: 0;
318
201
  </style>
@@ -73,5 +73,6 @@ onBeforeUnmount(() => close())
73
73
  </template>
74
74
 
75
75
  <style scoped>
76
- .n-ms{position:relative;width:100%;font-family:var(--n-font-sans)}.n-ms-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-ms-trigger{background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);padding:0.5rem 0.75rem;display:flex;justify-content:space-between;align-items:center;cursor:pointer;transition:all var(--n-transition-fast);color:var(--n-color-text);gap:var(--n-space-2);min-height:44px}.n-ms-trigger:focus-visible{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light),0 0 16px rgba(99,102,241,.25)}.n-ms.is-open .n-ms-trigger{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-ms-placeholder{color:var(--n-color-text-muted)}.n-ms-actions{display:flex;align-items:center;gap:0.25rem;flex-shrink:0}.n-ms-clear{background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;padding:0.15rem;font-size:var(--n-text-xs);border-radius:var(--n-radius-sm);line-height:1}.n-ms-clear:hover{color:var(--n-color-text)}.n-ms-arrow{color:var(--n-color-text-muted);transition:transform var(--n-transition-fast);font-size:var(--n-text-xs)}.is-open .n-ms-arrow{transform:rotate(180deg)}.n-ms-chips{display:flex;flex-wrap:wrap;gap:var(--n-space-2);align-items:center;min-width:0}.n-ms-chip{display:inline-flex;align-items:center;gap:0.35rem;padding:0.25rem 0.5rem;border-radius:999px;background:var(--n-color-glass);border:1px solid var(--n-color-border);font-size:var(--n-text-xs);line-height:1;max-width:12rem;transition:all .2s cubic-bezier(0.16,1,0.3,1)}.n-ms-chip:hover{background:var(--n-color-surface-hover)}.n-ms-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:10rem}.n-ms-chip-remove{background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;padding:0;line-height:1;display:flex;align-items:center}.n-ms-chip-remove:hover:not(:disabled){color:var(--n-color-text)}.n-ms-chip-remove:disabled{opacity:0.5;cursor:not-allowed}.n-ms-more{font-size:var(--n-text-xs);color:var(--n-color-text-muted)}.n-ms-dropdown{position:absolute;top:calc(100% + 0.5rem);left:0;width:100%;background:var(--n-color-glass);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);box-shadow:var(--n-shadow-lg),0 8px 32px rgba(0,0,0,.08);z-index:var(--n-z-dropdown);overflow:hidden;animation:n-ms-in .2s cubic-bezier(0.16,1,0.3,1);backdrop-filter:blur(16px)}@keyframes n-ms-in{from{opacity:0;transform:translateY(-8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.n-ms-dropdown.is-top{animation:n-ms-in-top .2s cubic-bezier(0.16,1,0.3,1)}@keyframes n-ms-in-top{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.n-ms-search{padding:var(--n-space-2);border-bottom:1px solid var(--n-color-border)}.n-ms-search-input{width:100%;background:var(--n-color-bg);border:1px solid var(--n-color-border);border-radius:var(--n-radius-sm);padding:var(--n-space-2) var(--n-space-3);color:var(--n-color-text);font-size:var(--n-text-sm);outline:none;font-family:inherit}.n-ms-search-input:focus{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-ms-options{max-height:260px;overflow-y:auto}.n-ms-option{width:100%;display:flex;align-items:center;gap:0.5rem;padding:0.7rem 1rem;background:transparent;border:none;color:var(--n-color-text-secondary);cursor:pointer;transition:all .15s cubic-bezier(0.16,1,0.3,1);text-align:left;position:relative}.n-ms-option::before{content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);width:3px;height:0;border-radius:0 3px 3px 0;background:var(--n-color-primary);transition:height .2s cubic-bezier(0.16,1,0.3,1)}.n-ms-option:hover:not(:disabled),.n-ms-option.is-focused{background:var(--n-color-glass);color:var(--n-color-text)}.n-ms-option:hover::before,.n-ms-option.is-focused::before{height:60%}.n-ms-option.is-selected{background:var(--n-color-primary-light);color:var(--n-color-primary);font-weight:var(--n-weight-semibold)}.n-ms-option:disabled,.n-ms-option.is-disabled{opacity:0.4;cursor:not-allowed}.n-ms-check{width:1.25rem;display:inline-flex;align-items:center;justify-content:center;font-size:var(--n-text-xs)}.n-ms-empty{padding:var(--n-space-4);color:var(--n-color-text-muted);text-align:center;font-size:var(--n-text-sm)}.is-disabled .n-ms-trigger{opacity:0.5;cursor:not-allowed}
76
+ .n-ms{position:relative;width:100%;font-family:var(--n-font-sans)}.n-ms-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-ms-trigger{background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);padding:0.5rem 0.75rem;display:flex;justify-content:space-between;align-items:center;cursor:pointer;transition:all var(--n-transition-fast);color:var(--n-color-text);gap:var(--n-space-2);min-height:44px}.n-ms-trigger:focus-visible{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light),0 0 16px rgba(99,102,241,.25)}.n-ms.is-open .n-ms-trigger{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-ms-placeholder{color:var(--n-color-text-muted)}.n-ms-actions{display:flex;align-items:center;gap:0.25rem;flex-shrink:0}.n-ms-clear{background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;padding:0.15rem;font-size:var(--n-text-xs);border-radius:var(--n-radius-sm);line-height:1}.n-ms-clear:hover{color:var(--n-color-text)}.n-ms-arrow{color:var(--n-color-text-muted);transition:transform var(--n-transition-fast);font-size:var(--n-text-xs)}.is-open .n-ms-arrow{transform:rotate(180deg)}.n-ms-chips{display:flex;flex-wrap:wrap;gap:var(--n-space-2);align-items:center;min-width:0}.n-ms-chip{display:inline-flex;align-items:center;gap:0.35rem;padding:0.25rem 0.5rem;border-radius:999px;background:var(--n-color-glass);border:1px solid var(--n-color-border);font-size:var(--n-text-xs);line-height:1;max-width:12rem;transition:all .2s cubic-bezier(0.16,1,0.3,1)}.n-ms-chip:hover{background:var(--n-color-surface-hover)}.n-ms-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:10rem}.n-ms-chip-remove{background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;padding:0;line-height:1;display:flex;align-items:center}.n-ms-chip-remove:hover:not(:disabled){color:var(--n-color-text)}.n-ms-chip-remove:disabled{opacity:0.5;cursor:not-allowed}.n-ms-more{font-size:var(--n-text-xs);color:var(--n-color-text-muted)}.n-ms-dropdown{position:absolute;top:calc(100% + 0.5rem);left:0;width:100%;background:var(--n-color-glass);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);box-shadow:var(--n-shadow-lg),0 8px 32px rgba(0,0,0,.08);z-index:var(--n-z-dropdown);overflow:hidden;animation:n-ms-in .2s cubic-bezier(0.16,1,0.3,1);backdrop-filter:blur(16px)}@keyframes n-ms-in{from{opacity:0; scale(.98)}to{opacity:1; scale(1)}}.n-ms-dropdown.is-top{animation:n-ms-in-top .2s cubic-bezier(0.16,1,0.3,1)}@keyframes n-ms-in-top{from{opacity:0; scale(.98)}to{opacity:1; scale(1)}}.n-ms-search{padding:var(--n-space-2);border-bottom:1px solid var(--n-color-border)}.n-ms-search-input{width:100%;background:var(--n-color-bg);border:1px solid var(--n-color-border);border-radius:var(--n-radius-sm);padding:var(--n-space-2) var(--n-space-3);color:var(--n-color-text);font-size:var(--n-text-sm);outline:none;font-family:inherit}.n-ms-search-input:focus{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-ms-options{max-height:260px;overflow-y:auto}.n-ms-option{width:100%;display:flex;align-items:center;gap:0.5rem;padding:0.7rem 1rem;background:transparent;border:none;color:var(--n-color-text-secondary);cursor:pointer;transition:all .15s cubic-bezier(0.16,1,0.3,1);text-align:left;position:relative}.n-ms-option::before{content:'';position:absolute;left:0;top:50%;width:3px;height:0;border-radius:0 3px 3px 0;background:var(--n-color-primary);transition:height .2s cubic-bezier(0.16,1,0.3,1)}.n-ms-option:hover:not(:disabled),.n-ms-option.is-focused{background:var(--n-color-glass);color:var(--n-color-text)}.n-ms-option:hover::before,.n-ms-option.is-focused::before{height:60%}.n-ms-option.is-selected{background:var(--n-color-primary-light);color:var(--n-color-primary);font-weight:var(--n-weight-semibold)}.n-ms-option:disabled,.n-ms-option.is-disabled{opacity:0.4;cursor:not-allowed}.n-ms-check{width:1.25rem;display:inline-flex;align-items:center;justify-content:center;font-size:var(--n-text-xs)}.n-ms-empty{padding:var(--n-space-4);color:var(--n-color-text-muted);text-align:center;font-size:var(--n-text-sm)}.is-disabled .n-ms-trigger{opacity:0.5;cursor:not-allowed}
77
+
77
78
  </style>