nexa-ui-kit 0.6.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 (114) hide show
  1. package/dist/NBadge.nexa +40 -0
  2. package/dist/NBottomSheet.nexa +124 -0
  3. package/dist/NButton.nexa +123 -0
  4. package/dist/NCard.nexa +74 -0
  5. package/dist/NInput.nexa +116 -0
  6. package/dist/NModal.nexa +165 -0
  7. package/dist/NSelect.nexa +169 -0
  8. package/dist/NToastContainer.nexa +86 -0
  9. package/dist/NTooltip.nexa +115 -0
  10. package/dist/components/NAlert.js +134 -0
  11. package/dist/components/NAlert.nexa +115 -0
  12. package/dist/components/NAutocomplete.js +94 -0
  13. package/dist/components/NAutocomplete.nexa +58 -0
  14. package/dist/components/NAvatar.js +75 -0
  15. package/dist/components/NAvatar.nexa +67 -0
  16. package/dist/components/NBadge.js +74 -0
  17. package/dist/components/NBadge.nexa +61 -0
  18. package/dist/components/NBottomSheet.js +149 -0
  19. package/dist/components/NBottomSheet.nexa +145 -0
  20. package/dist/components/NButton.js +284 -0
  21. package/dist/components/NButton.nexa +275 -0
  22. package/dist/components/NCard.js +117 -0
  23. package/dist/components/NCard.nexa +100 -0
  24. package/dist/components/NCheckbox.js +108 -0
  25. package/dist/components/NCheckbox.nexa +90 -0
  26. package/dist/components/NChips.js +72 -0
  27. package/dist/components/NChips.nexa +57 -0
  28. package/dist/components/NDataTable.js +252 -0
  29. package/dist/components/NDataTable.nexa +186 -0
  30. package/dist/components/NDatepicker.js +379 -0
  31. package/dist/components/NDatepicker.nexa +367 -0
  32. package/dist/components/NForm.js +132 -0
  33. package/dist/components/NForm.nexa +133 -0
  34. package/dist/components/NFormField.js +173 -0
  35. package/dist/components/NFormField.nexa +171 -0
  36. package/dist/components/NInput.js +311 -0
  37. package/dist/components/NInput.nexa +311 -0
  38. package/dist/components/NInputNumber.js +202 -0
  39. package/dist/components/NInputNumber.nexa +199 -0
  40. package/dist/components/NModal.js +221 -0
  41. package/dist/components/NModal.nexa +221 -0
  42. package/dist/components/NMultiSelect.js +156 -0
  43. package/dist/components/NMultiSelect.nexa +77 -0
  44. package/dist/components/NPaginator.js +117 -0
  45. package/dist/components/NPaginator.nexa +77 -0
  46. package/dist/components/NPassword.js +193 -0
  47. package/dist/components/NPassword.nexa +178 -0
  48. package/dist/components/NProgressBar.js +127 -0
  49. package/dist/components/NProgressBar.nexa +111 -0
  50. package/dist/components/NRadio.js +96 -0
  51. package/dist/components/NRadio.nexa +81 -0
  52. package/dist/components/NSelect.js +468 -0
  53. package/dist/components/NSelect.nexa +452 -0
  54. package/dist/components/NSkeleton.js +98 -0
  55. package/dist/components/NSkeleton.nexa +74 -0
  56. package/dist/components/NSwitch.js +92 -0
  57. package/dist/components/NSwitch.nexa +76 -0
  58. package/dist/components/NTabs.js +129 -0
  59. package/dist/components/NTabs.nexa +113 -0
  60. package/dist/components/NTag.js +108 -0
  61. package/dist/components/NTag.nexa +93 -0
  62. package/dist/components/NToastContainer.js +242 -0
  63. package/dist/components/NToastContainer.nexa +221 -0
  64. package/dist/components/NTooltip.js +163 -0
  65. package/dist/components/NTooltip.nexa +166 -0
  66. package/dist/components/NTreeMenu.js +151 -0
  67. package/dist/components/NTreeMenu.nexa +142 -0
  68. package/dist/index.d.ts +32 -0
  69. package/dist/index.js +34 -0
  70. package/dist/services/FloatingOverlay.d.ts +27 -0
  71. package/dist/services/FloatingOverlay.js +98 -0
  72. package/dist/services/FormValidation.d.ts +8 -0
  73. package/dist/services/FormValidation.js +46 -0
  74. package/dist/services/ToastService.d.ts +16 -0
  75. package/dist/services/ToastService.js +26 -0
  76. package/dist/styles/theme.d.ts +1 -0
  77. package/dist/styles/theme.js +144 -0
  78. package/package.json +32 -0
  79. package/src/components/NAlert.nexa +115 -0
  80. package/src/components/NAutocomplete.nexa +58 -0
  81. package/src/components/NAvatar.nexa +67 -0
  82. package/src/components/NBadge.nexa +61 -0
  83. package/src/components/NBottomSheet.nexa +145 -0
  84. package/src/components/NButton.nexa +275 -0
  85. package/src/components/NCard.nexa +100 -0
  86. package/src/components/NCheckbox.nexa +90 -0
  87. package/src/components/NChips.nexa +57 -0
  88. package/src/components/NDataTable.nexa +186 -0
  89. package/src/components/NDatepicker.nexa +367 -0
  90. package/src/components/NForm.nexa +133 -0
  91. package/src/components/NFormField.nexa +171 -0
  92. package/src/components/NInput.nexa +311 -0
  93. package/src/components/NInputNumber.nexa +199 -0
  94. package/src/components/NModal.nexa +221 -0
  95. package/src/components/NMultiSelect.nexa +77 -0
  96. package/src/components/NPaginator.nexa +77 -0
  97. package/src/components/NPassword.nexa +178 -0
  98. package/src/components/NProgressBar.nexa +111 -0
  99. package/src/components/NRadio.nexa +81 -0
  100. package/src/components/NSelect.nexa +452 -0
  101. package/src/components/NSkeleton.nexa +74 -0
  102. package/src/components/NSwitch.nexa +76 -0
  103. package/src/components/NTabs.nexa +113 -0
  104. package/src/components/NTag.nexa +93 -0
  105. package/src/components/NToastContainer.nexa +221 -0
  106. package/src/components/NTooltip.nexa +166 -0
  107. package/src/components/NTreeMenu.nexa +142 -0
  108. package/src/index.ts +36 -0
  109. package/src/services/FloatingOverlay.ts +133 -0
  110. package/src/services/FormValidation.ts +44 -0
  111. package/src/services/ToastService.ts +41 -0
  112. package/src/shims.d.ts +5 -0
  113. package/src/styles/theme.ts +146 -0
  114. package/src/styles/tokens.css +170 -0
@@ -0,0 +1,93 @@
1
+ <script setup>
2
+ const props = defineProps({
3
+ variant: { type: String, default: 'primary' },
4
+ size: { type: String, default: 'md' },
5
+ closable: { type: Boolean, default: false },
6
+ rounded: { type: Boolean, default: false }
7
+ })
8
+
9
+ const emit = defineEmits(['close'])
10
+ </script>
11
+
12
+ <template>
13
+ <span :class="['n-tag', `n-tag-${variant}`, `n-tag-${size}`, rounded ? 'is-rounded' : '']">
14
+ <slot />
15
+ <button v-if="closable" class="n-tag-close" @click="emit('close')">&times;</button>
16
+ </span>
17
+ </template>
18
+
19
+ <style scoped>
20
+ .n-tag {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ gap: var(--n-space-1);
24
+ padding: 0.2rem 0.6rem;
25
+ font-size: var(--n-text-xs);
26
+ font-weight: var(--n-weight-semibold);
27
+ border-radius: var(--n-radius-sm);
28
+ line-height: 1.4;
29
+ font-family: var(--n-font-sans);
30
+ white-space: nowrap;
31
+ border: 1px solid transparent;
32
+ }
33
+
34
+ .n-tag.is-rounded {
35
+ border-radius: var(--n-radius-full);
36
+ }
37
+
38
+ .n-tag-sm { padding: 0.1rem 0.4rem; font-size: 0.65rem; }
39
+ .n-tag-lg { padding: 0.35rem 0.8rem; font-size: var(--n-text-sm); }
40
+
41
+ .n-tag-primary {
42
+ background: var(--n-color-primary-light);
43
+ border-color: rgba(59, 130, 246, 0.25);
44
+ color: var(--n-color-primary);
45
+ }
46
+
47
+ .n-tag-success {
48
+ background: var(--n-color-success-light);
49
+ border-color: rgba(16, 185, 129, 0.25);
50
+ color: var(--n-color-success);
51
+ }
52
+
53
+ .n-tag-danger {
54
+ background: var(--n-color-danger-light);
55
+ border-color: rgba(239, 68, 68, 0.25);
56
+ color: var(--n-color-danger);
57
+ }
58
+
59
+ .n-tag-warning {
60
+ background: var(--n-color-warning-light);
61
+ border-color: rgba(245, 158, 11, 0.25);
62
+ color: var(--n-color-warning);
63
+ }
64
+
65
+ .n-tag-info {
66
+ background: var(--n-color-info-light);
67
+ border-color: rgba(6, 182, 212, 0.25);
68
+ color: var(--n-color-info);
69
+ }
70
+
71
+ .n-tag-secondary {
72
+ background: var(--n-color-surface-alt);
73
+ border-color: var(--n-color-border);
74
+ color: var(--n-color-text-secondary);
75
+ }
76
+
77
+ .n-tag-close {
78
+ background: transparent;
79
+ border: none;
80
+ cursor: pointer;
81
+ font-size: inherit;
82
+ line-height: 1;
83
+ padding: 0;
84
+ margin-left: var(--n-space-1);
85
+ color: inherit;
86
+ opacity: 0.6;
87
+ transition: opacity var(--n-transition-fast);
88
+ }
89
+
90
+ .n-tag-close:hover {
91
+ opacity: 1;
92
+ }
93
+ </style>
@@ -0,0 +1,221 @@
1
+ <script setup>
2
+ import { useToast } from '../services/ToastService.js'
3
+
4
+ const props = defineProps({
5
+ position: { type: String, default: 'top-right' }
6
+ })
7
+
8
+ const { toasts, remove } = useToast()
9
+
10
+ const positionClass = `is-${props.position.replace('-', '-')}`
11
+ </script>
12
+
13
+ <template>
14
+ <Teleport to="body">
15
+ <div class="n-toast-container" :class="positionClass">
16
+ <div
17
+ v-for="toast in toasts.value"
18
+ :key="toast.id"
19
+ class="n-toast"
20
+ :class="`is-${toast.type}`"
21
+ @click="remove(toast.id)"
22
+ >
23
+ <div class="n-toast-body">
24
+ <span class="n-toast-icon">
25
+ {{ toast.type === 'success' ? '✓' : toast.type === 'error' ? '✕' : toast.type === 'warning' ? '⚡' : 'ℹ' }}
26
+ </span>
27
+ <span class="n-toast-message">{{ toast.message }}</span>
28
+ <button class="n-toast-dismiss" @click.stop="remove(toast.id)" aria-label="Dismiss">&times;</button>
29
+ </div>
30
+ <div v-if="toast.duration > 0" class="n-toast-progress" :style="{ animationDuration: toast.duration + 'ms' }"></div>
31
+ </div>
32
+ </div>
33
+ </Teleport>
34
+ </template>
35
+
36
+ <style scoped>
37
+ .n-toast-container {
38
+ position: fixed;
39
+ z-index: var(--n-z-toast);
40
+ display: flex;
41
+ flex-direction: column;
42
+ gap: var(--n-space-3);
43
+ pointer-events: none;
44
+ padding: var(--n-space-4);
45
+ }
46
+
47
+ .is-top-right {
48
+ top: 0;
49
+ right: 0;
50
+ align-items: flex-end;
51
+ }
52
+
53
+ .is-top-left {
54
+ top: 0;
55
+ left: 0;
56
+ align-items: flex-start;
57
+ }
58
+
59
+ .is-bottom-right {
60
+ bottom: 0;
61
+ right: 0;
62
+ align-items: flex-end;
63
+ flex-direction: column-reverse;
64
+ }
65
+
66
+ .is-bottom-left {
67
+ bottom: 0;
68
+ left: 0;
69
+ align-items: flex-start;
70
+ flex-direction: column-reverse;
71
+ }
72
+
73
+ .is-top-center {
74
+ top: 0;
75
+ left: 50%;
76
+ transform: translateX(-50%);
77
+ align-items: center;
78
+ }
79
+
80
+ .n-toast {
81
+ pointer-events: auto;
82
+ min-width: 300px;
83
+ max-width: 420px;
84
+ background: var(--n-color-surface);
85
+ border: 1px solid var(--n-color-border);
86
+ border-radius: var(--n-radius-md);
87
+ overflow: hidden;
88
+ box-shadow: var(--n-shadow-lg);
89
+ cursor: pointer;
90
+ animation: n-toast-in 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
91
+ transition: all var(--n-transition-fast);
92
+ }
93
+
94
+ .n-toast:hover {
95
+ transform: scale(1.02);
96
+ background: var(--n-color-surface-alt);
97
+ }
98
+
99
+ @keyframes n-toast-in {
100
+ from {
101
+ opacity: 0;
102
+ transform: translateX(30px) scale(0.95);
103
+ }
104
+ to {
105
+ opacity: 1;
106
+ transform: translateX(0) scale(1);
107
+ }
108
+ }
109
+
110
+ .is-top-left .n-toast {
111
+ animation-name: n-toast-in-left;
112
+ }
113
+
114
+ @keyframes n-toast-in-left {
115
+ from {
116
+ opacity: 0;
117
+ transform: translateX(-30px) scale(0.95);
118
+ }
119
+ to {
120
+ opacity: 1;
121
+ transform: translateX(0) scale(1);
122
+ }
123
+ }
124
+
125
+ .is-bottom-right .n-toast,
126
+ .is-bottom-left .n-toast {
127
+ animation-name: n-toast-in-up;
128
+ }
129
+
130
+ @keyframes n-toast-in-up {
131
+ from {
132
+ opacity: 0;
133
+ transform: translateY(20px) scale(0.95);
134
+ }
135
+ to {
136
+ opacity: 1;
137
+ transform: translateY(0) scale(1);
138
+ }
139
+ }
140
+
141
+ .n-toast-body {
142
+ display: flex;
143
+ align-items: center;
144
+ gap: var(--n-space-3);
145
+ padding: var(--n-space-4) var(--n-space-5);
146
+ }
147
+
148
+ .n-toast-icon {
149
+ width: 28px;
150
+ height: 28px;
151
+ border-radius: var(--n-radius-full);
152
+ display: flex;
153
+ align-items: center;
154
+ justify-content: center;
155
+ font-size: var(--n-text-sm);
156
+ font-weight: var(--n-weight-extrabold);
157
+ flex-shrink: 0;
158
+ }
159
+
160
+ .is-success .n-toast-icon { background: var(--n-color-success); color: white; }
161
+ .is-error .n-toast-icon { background: var(--n-color-danger); color: white; }
162
+ .is-info .n-toast-icon { background: var(--n-color-primary); color: white; }
163
+ .is-warning .n-toast-icon { background: var(--n-color-warning); color: white; }
164
+
165
+ .n-toast-message {
166
+ color: var(--n-color-text);
167
+ font-size: var(--n-text-sm);
168
+ font-weight: var(--n-weight-medium);
169
+ flex: 1;
170
+ line-height: var(--n-leading-normal);
171
+ }
172
+
173
+ .n-toast-dismiss {
174
+ background: transparent;
175
+ border: none;
176
+ color: var(--n-color-text-muted);
177
+ font-size: var(--n-text-lg);
178
+ cursor: pointer;
179
+ padding: 0;
180
+ line-height: 1;
181
+ opacity: 0;
182
+ transition: opacity var(--n-transition-fast);
183
+ flex-shrink: 0;
184
+ }
185
+
186
+ .n-toast:hover .n-toast-dismiss {
187
+ opacity: 1;
188
+ }
189
+
190
+ .n-toast-dismiss:hover {
191
+ color: var(--n-color-text);
192
+ }
193
+
194
+ .n-toast-progress {
195
+ height: 3px;
196
+ background: var(--n-color-border);
197
+ position: relative;
198
+ overflow: hidden;
199
+ }
200
+
201
+ .n-toast-progress::after {
202
+ content: '';
203
+ position: absolute;
204
+ top: 0;
205
+ left: 0;
206
+ height: 100%;
207
+ width: 100%;
208
+ background: currentColor;
209
+ animation: n-toast-shrink linear forwards;
210
+ }
211
+
212
+ .is-success .n-toast-progress::after { background: var(--n-color-success); }
213
+ .is-error .n-toast-progress::after { background: var(--n-color-danger); }
214
+ .is-info .n-toast-progress::after { background: var(--n-color-primary); }
215
+ .is-warning .n-toast-progress::after { background: var(--n-color-warning); }
216
+
217
+ @keyframes n-toast-shrink {
218
+ from { transform: scaleX(1); }
219
+ to { transform: scaleX(0); }
220
+ }
221
+ </style>
@@ -0,0 +1,166 @@
1
+ <script setup>
2
+ import { signal } from 'nexa-framework'
3
+ import { trackFloatingOverlay } from '../services/FloatingOverlay.js'
4
+
5
+ const props = defineProps({
6
+ text: { type: String, default: '' },
7
+ position: { type: String, default: 'top' },
8
+ delay: { type: Number, default: 200 },
9
+ hideDelay: { type: Number, default: 100 }
10
+ })
11
+
12
+ const isVisible = signal(false)
13
+ const instanceId = `n-tt-${Math.random().toString(16).slice(2)}`
14
+ const popupStyle = signal({})
15
+ const resolvedPlacement = signal('top')
16
+ const rootEl = signal(null)
17
+ let stopTracking = null
18
+ let showTimer = null
19
+ let hideTimer = null
20
+
21
+ const startTracking = () => {
22
+ if (stopTracking) stopTracking()
23
+ stopTracking = trackFloatingOverlay({
24
+ isOpen: () => isVisible.value,
25
+ getAnchor: () => rootEl.value,
26
+ getPopup: () => document.querySelector(`[data-tooltip-popup="${instanceId}"]`),
27
+ placement: props.position,
28
+ align: 'center',
29
+ matchWidth: false,
30
+ minWidth: 0,
31
+ gap: 8,
32
+ margin: 8,
33
+ zIndex: 1000,
34
+ onUpdate: (result) => {
35
+ popupStyle.value = result.style
36
+ resolvedPlacement.value = result.placement
37
+ },
38
+ })
39
+ }
40
+
41
+ const stop = () => {
42
+ if (stopTracking) {
43
+ stopTracking()
44
+ stopTracking = null
45
+ }
46
+ }
47
+
48
+ const show = (e) => {
49
+ clearTimeout(hideTimer)
50
+ const target = e?.currentTarget || e?.target
51
+ rootEl.value = target?.closest ? target.closest(`[data-tooltip-root="${instanceId}"]`) : null
52
+ showTimer = setTimeout(() => {
53
+ isVisible.value = true
54
+ requestAnimationFrame(() => startTracking())
55
+ }, props.delay)
56
+ }
57
+
58
+ const hide = () => {
59
+ clearTimeout(showTimer)
60
+ hideTimer = setTimeout(() => {
61
+ isVisible.value = false
62
+ stop()
63
+ }, props.hideDelay)
64
+ }
65
+ </script>
66
+
67
+ <template>
68
+ <div
69
+ class="n-tooltip-wrapper"
70
+ :data-tooltip-root="instanceId"
71
+ @mouseenter="show"
72
+ @mouseleave="hide"
73
+ @focusin="show"
74
+ @focusout="hide"
75
+ >
76
+ <slot />
77
+ <Teleport to="body">
78
+ <div
79
+ v-if="isVisible.value"
80
+ class="n-tooltip"
81
+ :class="`is-${resolvedPlacement.value}`"
82
+ role="tooltip"
83
+ :data-tooltip-popup="instanceId"
84
+ :style="popupStyle.value"
85
+ >
86
+ {{ text }}
87
+ </div>
88
+ </Teleport>
89
+ </div>
90
+ </template>
91
+
92
+ <style scoped>
93
+ .n-tooltip-wrapper {
94
+ display: inline-block;
95
+ }
96
+
97
+ .n-tooltip {
98
+ background: var(--n-color-bg);
99
+ color: var(--n-color-text);
100
+ padding: var(--n-space-2) var(--n-space-3);
101
+ border-radius: var(--n-radius-sm);
102
+ font-size: var(--n-text-xs);
103
+ font-weight: var(--n-weight-medium);
104
+ white-space: nowrap;
105
+ z-index: var(--n-z-tooltip);
106
+ box-shadow: var(--n-shadow-lg);
107
+ border: 1px solid var(--n-color-border);
108
+ pointer-events: none;
109
+ animation: n-tooltip-in 0.2s ease-out;
110
+ }
111
+
112
+ @keyframes n-tooltip-in {
113
+ from { opacity: 0; transform: scale(0.95); }
114
+ to { opacity: 1; transform: scale(1); }
115
+ }
116
+
117
+ .is-top {
118
+ transform-origin: bottom center;
119
+ }
120
+
121
+ .is-bottom {
122
+ transform-origin: top center;
123
+ }
124
+
125
+ .is-left {
126
+ transform-origin: center right;
127
+ }
128
+
129
+ .is-right {
130
+ transform-origin: center left;
131
+ }
132
+
133
+ .n-tooltip::after {
134
+ content: '';
135
+ position: absolute;
136
+ border: 5px solid transparent;
137
+ }
138
+
139
+ .is-top::after {
140
+ top: 100%;
141
+ left: 50%;
142
+ transform: translateX(-50%);
143
+ border-top-color: var(--n-color-border);
144
+ }
145
+
146
+ .is-bottom::after {
147
+ bottom: 100%;
148
+ left: 50%;
149
+ transform: translateX(-50%);
150
+ border-bottom-color: var(--n-color-border);
151
+ }
152
+
153
+ .is-left::after {
154
+ left: 100%;
155
+ top: 50%;
156
+ transform: translateY(-50%);
157
+ border-left-color: var(--n-color-border);
158
+ }
159
+
160
+ .is-right::after {
161
+ right: 100%;
162
+ top: 50%;
163
+ transform: translateY(-50%);
164
+ border-right-color: var(--n-color-border);
165
+ }
166
+ </style>
@@ -0,0 +1,142 @@
1
+ <script setup>
2
+ import { signal, computed, h } from 'nexa-framework'
3
+
4
+ const props = defineProps({
5
+ items: { type: Array, default: () => [] },
6
+ selectable: { type: Boolean, default: true },
7
+ selected: { type: String, default: '' }
8
+ })
9
+
10
+ const emit = defineEmits(['update:selected', 'select'])
11
+
12
+ const expanded = signal({})
13
+
14
+ const toggleExpand = (id) => {
15
+ const current = { ...expanded.value }
16
+ current[id] = !current[id]
17
+ expanded.value = current
18
+ }
19
+
20
+ const selectItem = (item) => {
21
+ if (!props.selectable) return
22
+ emit('update:selected', item.id)
23
+ emit('select', item)
24
+ }
25
+
26
+ const hasChildren = (item) => item.children && item.children.length > 0
27
+ const isExpanded = (id) => expanded.value[id] === true
28
+ const isSelected = (id) => props.selected === id
29
+
30
+ const flatTree = computed(() => {
31
+ const result = []
32
+ function walk(items, depth) {
33
+ for (const item of items) {
34
+ result.push({ ...item, _depth: depth })
35
+ if (hasChildren(item) && isExpanded(item.id)) {
36
+ walk(item.children, depth + 1)
37
+ }
38
+ }
39
+ }
40
+ walk(props.items, 0)
41
+ return result
42
+ })
43
+
44
+ const toggle = (id, e) => {
45
+ e.stopPropagation()
46
+ toggleExpand(id)
47
+ }
48
+ </script>
49
+
50
+ <template>
51
+ <div class="n-tree-menu">
52
+ <div v-for="item in flatTree.value" :key="item.id"
53
+ class="n-tree-item"
54
+ :class="{ 'is-selected': isSelected(item.id) }"
55
+ :style="{ '--n-tree-depth': String(item._depth) }"
56
+ >
57
+ <div class="n-tree-row" @click="selectItem(item)">
58
+ <button v-if="hasChildren(item)"
59
+ class="n-tree-toggle"
60
+ :class="{ 'is-expanded': isExpanded(item.id) }"
61
+ @click="toggle(item.id, $event)"
62
+ >▶</button>
63
+ <span v-else class="n-tree-toggle-placeholder"></span>
64
+ <span v-if="item.icon" class="n-tree-icon">{{ item.icon }}</span>
65
+ <span class="n-tree-label">{{ item.label }}</span>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </template>
70
+
71
+ <style scoped>
72
+ .n-tree-menu {
73
+ font-family: var(--n-font-sans);
74
+ font-size: var(--n-text-sm);
75
+ user-select: none;
76
+ }
77
+
78
+ .n-tree-item {
79
+ --n-tree-depth: 0;
80
+ }
81
+
82
+ .n-tree-row {
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 0.35rem;
86
+ padding: 0.4rem 0.5rem;
87
+ padding-left: calc(0.5rem + var(--n-tree-depth, 0) * 1.25rem);
88
+ border-radius: var(--n-radius-sm);
89
+ cursor: pointer;
90
+ transition: all var(--n-transition-fast);
91
+ color: var(--n-color-text);
92
+ }
93
+
94
+ .n-tree-row:hover {
95
+ background: var(--n-color-surface-hover);
96
+ }
97
+
98
+ .n-tree-item.is-selected > .n-tree-row {
99
+ background: var(--n-color-primary-light);
100
+ color: var(--n-color-primary);
101
+ font-weight: var(--n-weight-semibold);
102
+ }
103
+
104
+ .n-tree-toggle {
105
+ background: none;
106
+ border: none;
107
+ color: var(--n-color-text-muted);
108
+ cursor: pointer;
109
+ font-size: 0.6rem;
110
+ width: 16px;
111
+ height: 16px;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ padding: 0;
116
+ transition: transform var(--n-transition-fast);
117
+ flex-shrink: 0;
118
+ }
119
+
120
+ .n-tree-toggle.is-expanded {
121
+ transform: rotate(90deg);
122
+ }
123
+
124
+ .n-tree-toggle-placeholder {
125
+ width: 16px;
126
+ height: 16px;
127
+ flex-shrink: 0;
128
+ }
129
+
130
+ .n-tree-icon {
131
+ font-size: 1rem;
132
+ flex-shrink: 0;
133
+ }
134
+
135
+ .n-tree-label {
136
+ flex: 1;
137
+ min-width: 0;
138
+ overflow: hidden;
139
+ text-overflow: ellipsis;
140
+ white-space: nowrap;
141
+ }
142
+ </style>
package/src/index.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { installTheme } from './styles/theme.js'
2
+ installTheme()
3
+
4
+ export { default as NButton } from './components/NButton.nexa'
5
+ export { default as NCard } from './components/NCard.nexa'
6
+ export { default as NInput } from './components/NInput.nexa'
7
+ export { default as NBadge } from './components/NBadge.nexa'
8
+ export { default as NModal } from './components/NModal.nexa'
9
+ export { default as NBottomSheet } from './components/NBottomSheet.nexa'
10
+ export { default as NSelect } from './components/NSelect.nexa'
11
+ export { default as NToastContainer } from './components/NToastContainer.nexa'
12
+ export { default as NTooltip } from './components/NTooltip.nexa'
13
+ export { default as NSwitch } from './components/NSwitch.nexa'
14
+ export { default as NCheckbox } from './components/NCheckbox.nexa'
15
+ export { default as NRadio } from './components/NRadio.nexa'
16
+ export { default as NAutocomplete } from './components/NAutocomplete.nexa'
17
+ export { default as NTabs } from './components/NTabs.nexa'
18
+ export { default as NAlert } from './components/NAlert.nexa'
19
+ export { default as NTag } from './components/NTag.nexa'
20
+ export { default as NProgressBar } from './components/NProgressBar.nexa'
21
+ export { default as NSkeleton } from './components/NSkeleton.nexa'
22
+ export { default as NAvatar } from './components/NAvatar.nexa'
23
+ export { default as NDatepicker } from './components/NDatepicker.nexa'
24
+ export { default as NTreeMenu } from './components/NTreeMenu.nexa'
25
+ export { default as NPassword } from './components/NPassword.nexa'
26
+ export { default as NForm } from './components/NForm.nexa'
27
+ export { default as NFormField } from './components/NFormField.nexa'
28
+ export { default as NChips } from './components/NChips.nexa'
29
+ export { default as NInputNumber } from './components/NInputNumber.nexa'
30
+ export { default as NMultiSelect } from './components/NMultiSelect.nexa'
31
+ export { default as NDataTable } from './components/NDataTable.nexa'
32
+ export { default as NPaginator } from './components/NPaginator.nexa'
33
+ export * from './services/ToastService.js'
34
+ export * from './services/FormValidation.js'
35
+ export { installTheme } from './styles/theme.js'
36
+