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,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,151 @@
1
+ import { signal, computed, h, hText, effect, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
2
+
3
+ const _sfc_main = defineComponent({
4
+ __scopeId: 'data-v-44b3942a',
5
+ __hmrId: 'NTreeMenu_nexa',
6
+ props: {
7
+ items: { type: Array, default: () => [] },
8
+ selectable: { type: Boolean, default: true },
9
+ selected: { type: String, default: '' }
10
+ },
11
+ emits: ['update:selected', 'select'],
12
+ setup(props, setupContext) {
13
+ const { emit, slots, slots: $slots } = setupContext
14
+ const expanded = signal({})
15
+ const toggleExpand = (id) => {
16
+ const current = { ...expanded.value }
17
+ current[id] = !current[id]
18
+ expanded.value = current
19
+ }
20
+ const selectItem = (item) => {
21
+ if (!props.selectable) return
22
+ emit('update:selected', item.id)
23
+ emit('select', item)
24
+ }
25
+ const hasChildren = (item) => item.children && item.children.length > 0
26
+ const isExpanded = (id) => expanded.value[id] === true
27
+ const isSelected = (id) => props.selected === id
28
+ const flatTree = computed(() => {
29
+ const result = []
30
+ function walk(items, depth) {
31
+ for (const item of items) {
32
+ result.push({ ...item, _depth: depth })
33
+ if (hasChildren(item) && isExpanded(item.id)) {
34
+ walk(item.children, depth + 1)
35
+ }
36
+ }
37
+ }
38
+ walk(props.items, 0)
39
+ return result
40
+ })
41
+ const toggle = (id, e) => {
42
+ e.stopPropagation()
43
+ toggleExpand(id)
44
+ }
45
+ return { expanded, toggleExpand, selectItem, hasChildren, isExpanded, isSelected, flatTree, toggle, $slots, emit }
46
+ }
47
+ })
48
+ // Injected render function
49
+ _sfc_main.render = function(ctx) {
50
+ const { expanded, toggleExpand, selectItem, hasChildren, isExpanded, isSelected, flatTree, toggle, $slots, emit, items, selectable, selected, Fragment: _ntc_Fragment } = ctx
51
+ return h('div', { class: "n-tree-menu", "data-v-44b3942a": "" }, [
52
+ "\n ",
53
+ flatTree.value.map((item, index) =>
54
+ h('div', { class: ["n-tree-item", { 'is-selected': isSelected(item.id) }], key: item.id, style: { '--n-tree-depth': String(item._depth) }, "data-v-44b3942a": "" }, [
55
+ "\n ",
56
+ h('div', { class: "n-tree-row", onClick: ($event) => { selectItem(item) }, "data-v-44b3942a": "" }, [
57
+ "\n ",
58
+ (hasChildren(item)) ? h('button', { class: ["n-tree-toggle", { 'is-expanded': isExpanded(item.id) }], onClick: ($event) => { toggle(item.id, $event) }, "data-v-44b3942a": "" }, [
59
+ "▶"
60
+ ]) : (true) ? h('span', { class: "n-tree-toggle-placeholder", "data-v-44b3942a": "" }) : null,
61
+ "\n ",
62
+ (item.icon) ? h('span', { class: "n-tree-icon", "data-v-44b3942a": "" }, [
63
+ item.icon
64
+ ]) : null,
65
+ h('span', { class: "n-tree-label", "data-v-44b3942a": "" }, [
66
+ item.label
67
+ ]),
68
+ "\n "
69
+ ]),
70
+ "\n "
71
+ ])
72
+ ),
73
+ "\n "
74
+ ])
75
+ }
76
+ _sfc_main.__scopeId = 'data-v-44b3942a'
77
+ _sfc_main.__hmrId = 'NTreeMenu_nexa'
78
+
79
+ export default _sfc_main
80
+
81
+ const __style = `.n-tree-menu[data-v-44b3942a]{
82
+ font-family: var(--n-font-sans);
83
+ font-size: var(--n-text-sm);
84
+ user-select: none;
85
+ }
86
+
87
+ .n-tree-item[data-v-44b3942a]{
88
+ --n-tree-depth: 0;
89
+ }
90
+
91
+ .n-tree-row[data-v-44b3942a]{
92
+ display: flex;
93
+ align-items: center;
94
+ gap: 0.35rem;
95
+ padding: 0.4rem 0.5rem;
96
+ padding-left: calc(0.5rem + var(--n-tree-depth, 0) * 1.25rem);
97
+ border-radius: var(--n-radius-sm);
98
+ cursor: pointer;
99
+ transition: all var(--n-transition-fast);
100
+ color: var(--n-color-text);
101
+ }
102
+
103
+ .n-tree-row[data-v-44b3942a]:hover{
104
+ background: var(--n-color-surface-hover);
105
+ }
106
+
107
+ .n-tree-item.is-selected > .n-tree-row[data-v-44b3942a]{
108
+ background: var(--n-color-primary-light);
109
+ color: var(--n-color-primary);
110
+ font-weight: var(--n-weight-semibold);
111
+ }
112
+
113
+ .n-tree-toggle[data-v-44b3942a]{
114
+ background: none;
115
+ border: none;
116
+ color: var(--n-color-text-muted);
117
+ cursor: pointer;
118
+ font-size: 0.6rem;
119
+ width: 16px;
120
+ height: 16px;
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: center;
124
+ padding: 0;
125
+ transition: transform var(--n-transition-fast);
126
+ flex-shrink: 0;
127
+ }
128
+
129
+ .n-tree-toggle.is-expanded[data-v-44b3942a]{
130
+ transform: rotate(90deg);
131
+ }
132
+
133
+ .n-tree-toggle-placeholder[data-v-44b3942a]{
134
+ width: 16px;
135
+ height: 16px;
136
+ flex-shrink: 0;
137
+ }
138
+
139
+ .n-tree-icon[data-v-44b3942a]{
140
+ font-size: 1rem;
141
+ flex-shrink: 0;
142
+ }
143
+
144
+ .n-tree-label[data-v-44b3942a]{
145
+ flex: 1;
146
+ min-width: 0;
147
+ overflow: hidden;
148
+ text-overflow: ellipsis;
149
+ white-space: nowrap;
150
+ }`
151
+ injectStyle('data-v-44b3942a', __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>
@@ -0,0 +1,32 @@
1
+ export { default as NButton } from './components/NButton.nexa';
2
+ export { default as NCard } from './components/NCard.nexa';
3
+ export { default as NInput } from './components/NInput.nexa';
4
+ export { default as NBadge } from './components/NBadge.nexa';
5
+ export { default as NModal } from './components/NModal.nexa';
6
+ export { default as NBottomSheet } from './components/NBottomSheet.nexa';
7
+ export { default as NSelect } from './components/NSelect.nexa';
8
+ export { default as NToastContainer } from './components/NToastContainer.nexa';
9
+ export { default as NTooltip } from './components/NTooltip.nexa';
10
+ export { default as NSwitch } from './components/NSwitch.nexa';
11
+ export { default as NCheckbox } from './components/NCheckbox.nexa';
12
+ export { default as NRadio } from './components/NRadio.nexa';
13
+ export { default as NAutocomplete } from './components/NAutocomplete.nexa';
14
+ export { default as NTabs } from './components/NTabs.nexa';
15
+ export { default as NAlert } from './components/NAlert.nexa';
16
+ export { default as NTag } from './components/NTag.nexa';
17
+ export { default as NProgressBar } from './components/NProgressBar.nexa';
18
+ export { default as NSkeleton } from './components/NSkeleton.nexa';
19
+ export { default as NAvatar } from './components/NAvatar.nexa';
20
+ export { default as NDatepicker } from './components/NDatepicker.nexa';
21
+ export { default as NTreeMenu } from './components/NTreeMenu.nexa';
22
+ export { default as NPassword } from './components/NPassword.nexa';
23
+ export { default as NForm } from './components/NForm.nexa';
24
+ export { default as NFormField } from './components/NFormField.nexa';
25
+ export { default as NChips } from './components/NChips.nexa';
26
+ export { default as NInputNumber } from './components/NInputNumber.nexa';
27
+ export { default as NMultiSelect } from './components/NMultiSelect.nexa';
28
+ export { default as NDataTable } from './components/NDataTable.nexa';
29
+ export { default as NPaginator } from './components/NPaginator.nexa';
30
+ export * from './services/ToastService.js';
31
+ export * from './services/FormValidation.js';
32
+ export { installTheme } from './styles/theme.js';
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ import { installTheme } from './styles/theme.js';
2
+ installTheme();
3
+ export { default as NButton } from './components/NButton.js';
4
+ export { default as NCard } from './components/NCard.js';
5
+ export { default as NInput } from './components/NInput.js';
6
+ export { default as NBadge } from './components/NBadge.js';
7
+ export { default as NModal } from './components/NModal.js';
8
+ export { default as NBottomSheet } from './components/NBottomSheet.js';
9
+ export { default as NSelect } from './components/NSelect.js';
10
+ export { default as NToastContainer } from './components/NToastContainer.js';
11
+ export { default as NTooltip } from './components/NTooltip.js';
12
+ export { default as NSwitch } from './components/NSwitch.js';
13
+ export { default as NCheckbox } from './components/NCheckbox.js';
14
+ export { default as NRadio } from './components/NRadio.js';
15
+ export { default as NAutocomplete } from './components/NAutocomplete.js';
16
+ export { default as NTabs } from './components/NTabs.js';
17
+ export { default as NAlert } from './components/NAlert.js';
18
+ export { default as NTag } from './components/NTag.js';
19
+ export { default as NProgressBar } from './components/NProgressBar.js';
20
+ export { default as NSkeleton } from './components/NSkeleton.js';
21
+ export { default as NAvatar } from './components/NAvatar.js';
22
+ export { default as NDatepicker } from './components/NDatepicker.js';
23
+ export { default as NTreeMenu } from './components/NTreeMenu.js';
24
+ export { default as NPassword } from './components/NPassword.js';
25
+ export { default as NForm } from './components/NForm.js';
26
+ export { default as NFormField } from './components/NFormField.js';
27
+ export { default as NChips } from './components/NChips.js';
28
+ export { default as NInputNumber } from './components/NInputNumber.js';
29
+ export { default as NMultiSelect } from './components/NMultiSelect.js';
30
+ export { default as NDataTable } from './components/NDataTable.js';
31
+ export { default as NPaginator } from './components/NPaginator.js';
32
+ export * from './services/ToastService.js';
33
+ export * from './services/FormValidation.js';
34
+ export { installTheme } from './styles/theme.js';
@@ -0,0 +1,27 @@
1
+ export type FloatingPlacement = 'auto' | 'top' | 'bottom' | 'left' | 'right';
2
+ export type FloatingAlign = 'start' | 'center' | 'end';
3
+ export type FloatingResult = {
4
+ style: Record<string, string | number>;
5
+ placement: Exclude<FloatingPlacement, 'auto'>;
6
+ };
7
+ type ComputeOptions = {
8
+ placement?: FloatingPlacement;
9
+ align?: FloatingAlign;
10
+ gap?: number;
11
+ margin?: number;
12
+ matchWidth?: boolean;
13
+ minWidth?: number;
14
+ maxWidth?: number;
15
+ zIndex?: number;
16
+ };
17
+ export declare const computeFloatingOverlay: (anchorEl: HTMLElement, popupEl: HTMLElement, options?: ComputeOptions) => FloatingResult;
18
+ type TrackOptions = ComputeOptions & {
19
+ isOpen: () => boolean;
20
+ getAnchor: () => HTMLElement | null;
21
+ getPopup: () => HTMLElement | null;
22
+ onUpdate: (result: FloatingResult) => void;
23
+ isEventInside?: (event: Event) => boolean;
24
+ onOutside?: (event: Event) => void;
25
+ };
26
+ export declare const trackFloatingOverlay: (options: TrackOptions) => (() => void);
27
+ export {};
@@ -0,0 +1,98 @@
1
+ const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
2
+ export const computeFloatingOverlay = (anchorEl, popupEl, options = {}) => {
3
+ const rect = anchorEl.getBoundingClientRect();
4
+ const viewportWidth = window.innerWidth;
5
+ const viewportHeight = window.innerHeight;
6
+ const margin = options.margin ?? 8;
7
+ const gap = options.gap ?? 6;
8
+ const align = options.align ?? 'start';
9
+ const maxWidth = options.maxWidth ?? viewportWidth - margin * 2;
10
+ const popupWidth = popupEl.offsetWidth || popupEl.getBoundingClientRect().width || 0;
11
+ const popupHeight = popupEl.offsetHeight || popupEl.getBoundingClientRect().height || 0;
12
+ const desiredWidth = options.matchWidth ? rect.width : popupWidth;
13
+ const width = clamp(Math.ceil(desiredWidth), options.minWidth ?? 240, Math.max(options.minWidth ?? 240, Math.min(maxWidth, viewportWidth - margin * 2)));
14
+ let placement = 'bottom';
15
+ const desiredPlacement = options.placement ?? 'auto';
16
+ if (desiredPlacement === 'top' || desiredPlacement === 'bottom' || desiredPlacement === 'left' || desiredPlacement === 'right') {
17
+ placement = desiredPlacement;
18
+ }
19
+ else {
20
+ const spaceBelow = viewportHeight - rect.bottom;
21
+ const spaceAbove = rect.top;
22
+ const fitsBottom = spaceBelow >= popupHeight + margin;
23
+ const fitsTop = spaceAbove >= popupHeight + margin;
24
+ if (!fitsBottom && fitsTop)
25
+ placement = 'top';
26
+ else if (!fitsTop && fitsBottom)
27
+ placement = 'bottom';
28
+ else
29
+ placement = spaceBelow >= spaceAbove ? 'bottom' : 'top';
30
+ }
31
+ let left = rect.left;
32
+ let top = rect.bottom + gap;
33
+ if (placement === 'top' || placement === 'bottom') {
34
+ if (align === 'center') {
35
+ left = rect.left + rect.width / 2 - width / 2;
36
+ }
37
+ else if (align === 'end') {
38
+ left = rect.right - width;
39
+ }
40
+ else {
41
+ left = rect.left;
42
+ }
43
+ left = clamp(left, margin, viewportWidth - width - margin);
44
+ top = placement === 'top' ? rect.top - gap - popupHeight : rect.bottom + gap;
45
+ top = clamp(top, margin, viewportHeight - popupHeight - margin);
46
+ }
47
+ else {
48
+ left = placement === 'left' ? rect.left - gap - width : rect.right + gap;
49
+ left = clamp(left, margin, viewportWidth - width - margin);
50
+ if (align === 'center') {
51
+ top = rect.top + rect.height / 2 - popupHeight / 2;
52
+ }
53
+ else if (align === 'end') {
54
+ top = rect.bottom - popupHeight;
55
+ }
56
+ else {
57
+ top = rect.top;
58
+ }
59
+ top = clamp(top, margin, viewportHeight - popupHeight - margin);
60
+ }
61
+ const style = {
62
+ position: 'fixed',
63
+ top: `${Math.round(top)}px`,
64
+ left: `${Math.round(left)}px`,
65
+ width: `${Math.round(width)}px`,
66
+ zIndex: options.zIndex ?? 9999,
67
+ };
68
+ return { style, placement };
69
+ };
70
+ export const trackFloatingOverlay = (options) => {
71
+ const update = () => {
72
+ if (!options.isOpen())
73
+ return;
74
+ const anchor = options.getAnchor();
75
+ const popup = options.getPopup();
76
+ if (!anchor || !popup)
77
+ return;
78
+ options.onUpdate(computeFloatingOverlay(anchor, popup, options));
79
+ };
80
+ const onScrollOrResize = () => update();
81
+ const onPointerDown = (e) => {
82
+ if (!options.isOpen())
83
+ return;
84
+ if (options.isEventInside && options.isEventInside(e))
85
+ return;
86
+ options.onOutside?.(e);
87
+ };
88
+ update();
89
+ requestAnimationFrame(update);
90
+ window.addEventListener('resize', onScrollOrResize);
91
+ window.addEventListener('scroll', onScrollOrResize, true);
92
+ document.addEventListener('mousedown', onPointerDown);
93
+ return () => {
94
+ window.removeEventListener('resize', onScrollOrResize);
95
+ window.removeEventListener('scroll', onScrollOrResize, true);
96
+ document.removeEventListener('mousedown', onPointerDown);
97
+ };
98
+ };
@@ -0,0 +1,8 @@
1
+ export type FormRule = (value: any, values: Record<string, any>) => string | null | undefined | Promise<string | null | undefined>;
2
+ export declare const required: (message?: string) => FormRule;
3
+ export declare const minLength: (length: number, message?: string) => FormRule;
4
+ export declare const maxLength: (length: number, message?: string) => FormRule;
5
+ export declare const pattern: (re: RegExp, message?: string) => FormRule;
6
+ export declare const email: (message?: string) => FormRule;
7
+ export declare const sameAs: (otherField: string, message?: string) => FormRule;
8
+ export declare const asyncRule: (rule: FormRule, delayMs?: number) => FormRule;