nexa-ui-kit 0.9.0 → 0.11.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.
- package/dist/components/NAlert.js +48 -27
- package/dist/components/NAlert.nexa +12 -6
- package/dist/components/NAutocomplete.js +24 -19
- package/dist/components/NAutocomplete.nexa +3 -3
- package/dist/components/NBottomSheet.js +17 -17
- package/dist/components/NBottomSheet.nexa +2 -2
- package/dist/components/NButton.js +58 -58
- package/dist/components/NButton.nexa +10 -9
- package/dist/components/NCard.js +1 -1
- package/dist/components/NCard.nexa +1 -1
- package/dist/components/NCheckbox.js +22 -18
- package/dist/components/NCheckbox.nexa +2 -1
- package/dist/components/NChips.js +12 -9
- package/dist/components/NChips.nexa +1 -1
- package/dist/components/NDataTable.js +359 -41
- package/dist/components/NDataTable.nexa +318 -10
- package/dist/components/NDatepicker.js +51 -42
- package/dist/components/NDatepicker.nexa +3 -3
- package/dist/components/NInput.js +50 -40
- package/dist/components/NInput.nexa +4 -3
- package/dist/components/NInputNumber.js +17 -12
- package/dist/components/NInputNumber.nexa +2 -2
- package/dist/components/NModal.js +33 -27
- package/dist/components/NModal.nexa +4 -4
- package/dist/components/NMultiSelect.js +46 -37
- package/dist/components/NMultiSelect.nexa +3 -3
- package/dist/components/NPaginator.js +28 -20
- package/dist/components/NPaginator.nexa +4 -4
- package/dist/components/NPassword.js +60 -46
- package/dist/components/NPassword.nexa +5 -4
- package/dist/components/NProgressBar.js +4 -4
- package/dist/components/NProgressBar.nexa +4 -4
- package/dist/components/NSelect.js +67 -62
- package/dist/components/NSelect.nexa +4 -4
- package/dist/components/NTag.js +26 -23
- package/dist/components/NTag.nexa +6 -6
- package/dist/components/NToastContainer.js +64 -48
- package/dist/components/NToastContainer.nexa +6 -3
- package/dist/components/NTreeMenu.js +23 -21
- package/dist/components/NTreeMenu.nexa +1 -1
- package/dist/styles/tokens.css +18 -0
- package/package.json +4 -4
- package/src/components/NAlert.nexa +12 -6
- package/src/components/NAutocomplete.nexa +3 -3
- package/src/components/NBottomSheet.nexa +2 -2
- package/src/components/NButton.nexa +10 -9
- package/src/components/NCard.nexa +1 -1
- package/src/components/NCheckbox.nexa +2 -1
- package/src/components/NChips.nexa +1 -1
- package/src/components/NDataTable.nexa +318 -10
- package/src/components/NDatepicker.nexa +3 -3
- package/src/components/NInput.nexa +4 -3
- package/src/components/NInputNumber.nexa +2 -2
- package/src/components/NModal.nexa +4 -4
- package/src/components/NMultiSelect.nexa +3 -3
- package/src/components/NPaginator.nexa +4 -4
- package/src/components/NPassword.nexa +5 -4
- package/src/components/NProgressBar.nexa +4 -4
- package/src/components/NSelect.nexa +4 -4
- package/src/components/NTag.nexa +6 -6
- package/src/components/NToastContainer.nexa +6 -3
- package/src/components/NTreeMenu.nexa +1 -1
- package/src/styles/tokens.css +18 -0
|
@@ -46,6 +46,7 @@ const btnClass = computed(() => {
|
|
|
46
46
|
:class="btnClass.value"
|
|
47
47
|
:type="type"
|
|
48
48
|
:disabled="disabled || loading"
|
|
49
|
+
:aria-busy="loading ? 'true' : undefined"
|
|
49
50
|
@click="handleClick"
|
|
50
51
|
>
|
|
51
52
|
<span v-if="loading" class="n-btn-loader"></span>
|
|
@@ -123,11 +124,11 @@ const btnClass = computed(() => {
|
|
|
123
124
|
.n-btn-success {
|
|
124
125
|
background: linear-gradient(135deg, var(--n-color-success) 0%, var(--n-color-success-hover) 100%);
|
|
125
126
|
color: white;
|
|
126
|
-
box-shadow:
|
|
127
|
+
box-shadow: var(--n-shadow-glow-success);
|
|
127
128
|
}
|
|
128
129
|
.n-btn-success:hover:not(:disabled) {
|
|
129
130
|
transform: translateY(-2px);
|
|
130
|
-
box-shadow:
|
|
131
|
+
box-shadow: var(--n-shadow-glow-success);
|
|
131
132
|
}
|
|
132
133
|
.n-btn-success:active:not(:disabled) {
|
|
133
134
|
transform: translateY(0) scale(0.97);
|
|
@@ -137,11 +138,11 @@ const btnClass = computed(() => {
|
|
|
137
138
|
.n-btn-warning {
|
|
138
139
|
background: linear-gradient(135deg, var(--n-color-warning) 0%, var(--n-color-warning-hover) 100%);
|
|
139
140
|
color: white;
|
|
140
|
-
box-shadow:
|
|
141
|
+
box-shadow: var(--n-shadow-glow-warning);
|
|
141
142
|
}
|
|
142
143
|
.n-btn-warning:hover:not(:disabled) {
|
|
143
144
|
transform: translateY(-2px);
|
|
144
|
-
box-shadow:
|
|
145
|
+
box-shadow: var(--n-shadow-glow-warning);
|
|
145
146
|
}
|
|
146
147
|
.n-btn-warning:active:not(:disabled) {
|
|
147
148
|
transform: translateY(0) scale(0.97);
|
|
@@ -151,11 +152,11 @@ const btnClass = computed(() => {
|
|
|
151
152
|
.n-btn-info {
|
|
152
153
|
background: linear-gradient(135deg, var(--n-color-info) 0%, var(--n-color-info-hover) 100%);
|
|
153
154
|
color: white;
|
|
154
|
-
box-shadow:
|
|
155
|
+
box-shadow: var(--n-shadow-glow-info);
|
|
155
156
|
}
|
|
156
157
|
.n-btn-info:hover:not(:disabled) {
|
|
157
158
|
transform: translateY(-2px);
|
|
158
|
-
box-shadow:
|
|
159
|
+
box-shadow: var(--n-shadow-glow-info);
|
|
159
160
|
}
|
|
160
161
|
.n-btn-info:active:not(:disabled) {
|
|
161
162
|
transform: translateY(0) scale(0.97);
|
|
@@ -165,11 +166,11 @@ const btnClass = computed(() => {
|
|
|
165
166
|
.n-btn-danger {
|
|
166
167
|
background: linear-gradient(135deg, var(--n-color-danger) 0%, var(--n-color-danger-hover) 100%);
|
|
167
168
|
color: white;
|
|
168
|
-
box-shadow:
|
|
169
|
+
box-shadow: var(--n-shadow-glow-danger);
|
|
169
170
|
}
|
|
170
171
|
.n-btn-danger:hover:not(:disabled) {
|
|
171
172
|
transform: translateY(-2px);
|
|
172
|
-
box-shadow:
|
|
173
|
+
box-shadow: var(--n-shadow-glow-danger);
|
|
173
174
|
}
|
|
174
175
|
.n-btn-danger:active:not(:disabled) {
|
|
175
176
|
transform: translateY(0) scale(0.97);
|
|
@@ -258,7 +259,7 @@ const btnClass = computed(() => {
|
|
|
258
259
|
.n-btn-ripple {
|
|
259
260
|
position: absolute;
|
|
260
261
|
border-radius: var(--n-radius-full);
|
|
261
|
-
background:
|
|
262
|
+
background: var(--n-color-glass);
|
|
262
263
|
width: 20px;
|
|
263
264
|
height: 20px;
|
|
264
265
|
margin-left: -10px;
|
|
@@ -102,7 +102,7 @@ const props = defineProps({
|
|
|
102
102
|
|
|
103
103
|
.n-card-footer {
|
|
104
104
|
padding: var(--n-space-4) var(--n-space-6);
|
|
105
|
-
background:
|
|
105
|
+
background: var(--n-color-glass);
|
|
106
106
|
border-top: 1px solid var(--n-color-border);
|
|
107
107
|
margin-top: auto;
|
|
108
108
|
}
|
|
@@ -18,7 +18,8 @@ const toggle = () => {
|
|
|
18
18
|
<label class="n-checkbox" :class="{ 'is-checked': modelValue && !indeterminate, 'is-indeterminate': indeterminate, 'is-disabled': disabled }">
|
|
19
19
|
<div class="n-checkbox-box" @click="toggle">
|
|
20
20
|
<span class="n-checkbox-icon">
|
|
21
|
-
|
|
21
|
+
<svg v-if="indeterminate" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" focusable="false" aria-hidden="true"><line x1="4" y1="12" x2="20" y2="12"/></svg>
|
|
22
|
+
<svg v-else viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
|
22
23
|
</span>
|
|
23
24
|
</div>
|
|
24
25
|
<span v-if="label" class="n-checkbox-label">{{ label }}</span>
|
|
@@ -47,7 +47,7 @@ const removeAt = (index) => {
|
|
|
47
47
|
<div class="n-chips" :class="{ 'is-disabled': disabled }">
|
|
48
48
|
<div v-for="(chip, i) in chips.value" :key="String(chip.value) + ':' + i" class="n-chip">
|
|
49
49
|
<span class="n-chip-label">{{ chip.label }}</span>
|
|
50
|
-
<button v-if="removable" type="button" class="n-chip-remove" :disabled="disabled" aria-label="Remove" @click="removeAt(i)"
|
|
50
|
+
<button v-if="removable" type="button" class="n-chip-remove" :disabled="disabled" aria-label="Remove" @click="removeAt(i)"><svg viewBox="0 0 24 24" width="12" height="12" 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>
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
53
53
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { signal, computed, effect } from 'nexa-framework'
|
|
3
3
|
import NPaginator from './NPaginator.nexa'
|
|
4
|
-
const props = defineProps({ value: { type: Array, default: () => [] }, columns: { type: Array, default: () => [] }, stripedRows: { type: Boolean, default: false }, hoverRows: { type: Boolean, default: true }, size: { type: String, default: 'md' }, scrollable: { type: Boolean, default: true }, paginator: { type: Boolean, default: true }, rows: { type: Number, default: 10 }, first: { type: Number, default: 0 }, rowsPerPageOptions: { type: Array, default: () => [10, 20, 50] }, selectionMode: { type: String, default: '' }, selection: { type: null, default: null }, dataKey: { type: String, default: '' }, sortField: { type: String, default: '' }, sortOrder: { type: Number, default: 1 }, resizableColumns: { type: Boolean, default: true }, columnResizeMode: { type: String, default: 'fit' }, filterDisplay: { type: String, default: 'row' }, globalFilter: { type: String, default: '' }, globalFilterFields: { type: Array, default: null }, filters: { type: null, default: null }, lazy: { type: Boolean, default: false }, totalRecords: { type: Number, default: 0 }, emptyMessage: { type: String, default: 'No records found' }, showGridlines: { type: Boolean, default: false } })
|
|
4
|
+
const props = defineProps({ value: { type: Array, default: () => [] }, columns: { type: Array, default: () => [] }, stripedRows: { type: Boolean, default: false }, hoverRows: { type: Boolean, default: true }, size: { type: String, default: 'md' }, scrollable: { type: Boolean, default: true }, paginator: { type: Boolean, default: true }, rows: { type: Number, default: 10 }, first: { type: Number, default: 0 }, rowsPerPageOptions: { type: Array, default: () => [10, 20, 50] }, selectionMode: { type: String, default: '' }, selection: { type: null, default: null }, dataKey: { type: String, default: '' }, sortField: { type: String, default: '' }, sortOrder: { type: Number, default: 1 }, resizableColumns: { type: Boolean, default: true }, columnResizeMode: { type: String, default: 'fit' }, filterDisplay: { type: String, default: 'row' }, globalFilter: { type: String, default: '' }, globalFilterFields: { type: Array, default: null }, filters: { type: null, default: null }, lazy: { type: Boolean, default: false }, totalRecords: { type: Number, default: 0 }, emptyMessage: { type: String, default: 'No records found' }, showGridlines: { type: Boolean, default: false }, searchPlaceholder: { type: String, default: 'Search...' }, filterPlaceholder: { type: String, default: 'Filter' }, loading: { type: Boolean, default: false } })
|
|
5
5
|
const emit = defineEmits(['update:first', 'update:rows', 'update:selection', 'update:sortField', 'update:sortOrder', 'update:globalFilter', 'update:filters', 'updateFirst', 'updateRows', 'updateSelection', 'updateSortField', 'updateSortOrder', 'updateGlobalFilter', 'updateFilters', 'page', 'rowSelect', 'rowUnselect', 'sort', 'filter'])
|
|
6
6
|
const internalFirst = signal(props.first || 0)
|
|
7
7
|
const internalRows = signal(props.rows || 10)
|
|
@@ -163,29 +163,47 @@ const startResize = (e) => { if (!props.resizableColumns) return; const field =
|
|
|
163
163
|
</script>
|
|
164
164
|
|
|
165
165
|
<template>
|
|
166
|
-
|
|
167
|
-
<div class="n-dt-toolbar"
|
|
166
|
+
<div class="n-dt" :class="[`n-dt-${size}`, showGridlines ? 'is-grid' : '', scrollable ? 'is-scroll' : '']" :aria-busy="loading ? 'true' : undefined">
|
|
167
|
+
<div class="n-dt-toolbar">
|
|
168
|
+
<div class="n-dt-global">
|
|
169
|
+
<svg 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"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
|
170
|
+
<input class="n-dt-global-input" :value="effectiveFilters.value.__global || ''" :placeholder="searchPlaceholder" @input="setGlobal" />
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
168
173
|
<div class="n-dt-wrapper">
|
|
169
174
|
<table class="n-dt-table" :class="{ 'is-striped': stripedRows, 'is-hover': hoverRows }">
|
|
170
175
|
<thead class="n-dt-thead">
|
|
171
176
|
<tr class="n-dt-head-row">
|
|
172
|
-
<th v-if="selectionMode" class="n-dt-th is-selection"
|
|
177
|
+
<th v-if="selectionMode" class="n-dt-th is-selection">
|
|
178
|
+
<button v-if="selectionMode === 'multiple'" type="button" class="n-dt-selectbox" :class="{ 'is-checked': allVisibleSelected.value }" @click.stop="toggleAllVisible" :aria-label="allVisibleSelected.value ? 'Deselect all' : 'Select all'">
|
|
179
|
+
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
|
180
|
+
</button>
|
|
181
|
+
</th>
|
|
173
182
|
<th v-for="col in normalizeColumns.value" :key="col.field" class="n-dt-th" :class="[`is-${col.align}`, col.sortable ? 'is-sortable' : '']" :style="{ width: getWidth(col) || undefined, minWidth: col.minWidth }" :data-field="col.field" @click="onSortClick">
|
|
174
183
|
<div class="n-dt-th-content">
|
|
175
184
|
<span class="n-dt-th-text">{{ $slots.value && $slots.value[`header-${col.field}`] ? $slots[`header-${col.field}`]({ column: col }) : getHeaderContent(col) }}</span>
|
|
176
185
|
<span v-if="col.sortable" class="n-dt-sort" :class="{ 'is-active': internalSortField.value === col.field }">
|
|
177
|
-
<
|
|
178
|
-
<
|
|
186
|
+
<svg class="n-dt-sort-arrow n-dt-sort-arrow-up" :class="{ 'is-on': internalSortField.value === col.field && internalSortOrder.value === 1 }" 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="M12 19V5M5 12l7-7 7 7"/></svg>
|
|
187
|
+
<svg class="n-dt-sort-arrow n-dt-sort-arrow-down" :class="{ 'is-on': internalSortField.value === col.field && internalSortOrder.value === -1 }" 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="M12 5v14M19 12l-7 7-7-7"/></svg>
|
|
179
188
|
</span>
|
|
180
189
|
</div>
|
|
181
190
|
<span v-if="resizableColumns" class="n-dt-resizer" :data-field="col.field" @mousedown="startResize"></span>
|
|
182
191
|
</th>
|
|
183
192
|
</tr>
|
|
184
|
-
<tr v-if="filterDisplay === 'row'" class="n-dt-filter-row"
|
|
193
|
+
<tr v-if="filterDisplay === 'row'" class="n-dt-filter-row">
|
|
194
|
+
<th v-if="selectionMode" class="n-dt-th is-selection"></th>
|
|
195
|
+
<th v-for="col in normalizeColumns.value" :key="col.field" class="n-dt-th" :class="`is-${col.align}`" :style="{ width: getWidth(col) || undefined, minWidth: col.minWidth }">
|
|
196
|
+
<input v-if="col.filterable" class="n-dt-filter" :data-field="col.field" :value="(effectiveFilters.value[col.field]?.value) || ''" :placeholder="filterPlaceholder" @input="onColumnFilterInput" />
|
|
197
|
+
</th>
|
|
198
|
+
</tr>
|
|
185
199
|
</thead>
|
|
186
200
|
<tbody class="n-dt-tbody">
|
|
187
201
|
<tr v-for="(row, i) in visibleRows.value" :key="getRowKey(row, i + internalFirst.value)" class="n-dt-row" :class="{ 'is-selected': isRowSelected(row, i + internalFirst.value) }" @click="toggleRowSelection(row, i + internalFirst.value)">
|
|
188
|
-
<td v-if="selectionMode" class="n-dt-td is-selection"
|
|
202
|
+
<td v-if="selectionMode" class="n-dt-td is-selection">
|
|
203
|
+
<button v-if="selectionMode === 'multiple'" type="button" class="n-dt-selectbox" :class="{ 'is-checked': isRowSelected(row, i + internalFirst.value) }" @click.stop="toggleRowSelection(row, i + internalFirst.value)" :aria-label="isRowSelected(row, i + internalFirst.value) ? 'Deselect row' : 'Select row'">
|
|
204
|
+
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
|
205
|
+
</button>
|
|
206
|
+
</td>
|
|
189
207
|
<td v-for="col in normalizeColumns.value" :key="col.field" class="n-dt-td" :class="`is-${col.align}`" :style="{ width: getWidth(col) || undefined, minWidth: col.minWidth }">
|
|
190
208
|
{{ $slots.value && $slots.value[`body-${col.field}`] ? $slots[`body-${col.field}`]({ data: row, column: col, index: i + internalFirst.value }) : getCellContent(row, col, i + internalFirst.value) }}
|
|
191
209
|
</td>
|
|
@@ -199,5 +217,295 @@ const startResize = (e) => { if (!props.resizableColumns) return; const field =
|
|
|
199
217
|
</template>
|
|
200
218
|
|
|
201
219
|
<style scoped>
|
|
202
|
-
.n-dt
|
|
203
|
-
|
|
220
|
+
.n-dt {
|
|
221
|
+
border: 1px solid var(--n-color-border);
|
|
222
|
+
border-radius: var(--n-radius-lg);
|
|
223
|
+
background: var(--n-color-surface);
|
|
224
|
+
overflow: hidden;
|
|
225
|
+
font-family: var(--n-font-sans);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.n-dt.is-grid {
|
|
229
|
+
border-color: var(--n-color-border);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.n-dt.is-grid .n-dt-th,
|
|
233
|
+
.n-dt.is-grid .n-dt-td {
|
|
234
|
+
border: 1px solid var(--n-color-border);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.n-dt-toolbar {
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
justify-content: space-between;
|
|
241
|
+
padding: 0.75rem 1rem;
|
|
242
|
+
border-bottom: 1px solid var(--n-color-border);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.n-dt-global {
|
|
246
|
+
display: flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
gap: 0.5rem;
|
|
249
|
+
color: var(--n-color-text-muted);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.n-dt-global-input {
|
|
253
|
+
width: 260px;
|
|
254
|
+
max-width: 100%;
|
|
255
|
+
background: transparent;
|
|
256
|
+
border: 1px solid var(--n-color-border);
|
|
257
|
+
border-radius: var(--n-radius-md);
|
|
258
|
+
padding: 0.45rem 0.75rem;
|
|
259
|
+
color: var(--n-color-text);
|
|
260
|
+
font-size: var(--n-text-sm);
|
|
261
|
+
outline: none;
|
|
262
|
+
box-sizing: border-box;
|
|
263
|
+
transition: border-color 0.15s ease;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.n-dt-global-input:focus {
|
|
267
|
+
border-color: var(--n-color-primary);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.n-dt-wrapper {
|
|
271
|
+
width: 100%;
|
|
272
|
+
overflow: auto;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.n-dt-table {
|
|
276
|
+
width: 100%;
|
|
277
|
+
border-collapse: collapse;
|
|
278
|
+
table-layout: fixed;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.n-dt-thead {
|
|
282
|
+
background: var(--n-color-surface);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.n-dt-th {
|
|
286
|
+
position: relative;
|
|
287
|
+
padding: 0.65rem 0.85rem;
|
|
288
|
+
border-bottom: 2px solid var(--n-color-border);
|
|
289
|
+
color: var(--n-color-text-secondary);
|
|
290
|
+
font-size: var(--n-text-sm);
|
|
291
|
+
font-weight: var(--n-weight-semibold);
|
|
292
|
+
user-select: none;
|
|
293
|
+
vertical-align: middle;
|
|
294
|
+
text-align: left;
|
|
295
|
+
background: var(--n-color-surface);
|
|
296
|
+
transition: background 0.15s ease;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.n-dt-th.is-sortable {
|
|
300
|
+
cursor: pointer;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.n-dt-th.is-sortable:hover {
|
|
304
|
+
background: var(--n-color-glass);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.n-dt-th.is-right {
|
|
308
|
+
text-align: right;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.n-dt-th.is-center {
|
|
312
|
+
text-align: center;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.n-dt-th.is-selection {
|
|
316
|
+
width: 3rem;
|
|
317
|
+
text-align: center;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.n-dt-th-content {
|
|
321
|
+
display: flex;
|
|
322
|
+
align-items: center;
|
|
323
|
+
gap: 0.35rem;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.n-dt-th.is-right .n-dt-th-content {
|
|
327
|
+
justify-content: flex-end;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.n-dt-th.is-center .n-dt-th-content {
|
|
331
|
+
justify-content: center;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.n-dt-th-text {
|
|
335
|
+
overflow: hidden;
|
|
336
|
+
text-overflow: ellipsis;
|
|
337
|
+
white-space: nowrap;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.n-dt-sort {
|
|
341
|
+
display: inline-flex;
|
|
342
|
+
flex-direction: column;
|
|
343
|
+
align-items: center;
|
|
344
|
+
gap: 0;
|
|
345
|
+
line-height: 1;
|
|
346
|
+
margin-left: auto;
|
|
347
|
+
flex-shrink: 0;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.n-dt-sort-arrow {
|
|
351
|
+
display: block;
|
|
352
|
+
color: var(--n-color-border);
|
|
353
|
+
transition: color 0.15s ease;
|
|
354
|
+
margin: -3px 0;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.n-dt-sort-arrow-up.is-on {
|
|
358
|
+
color: var(--n-color-primary);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.n-dt-sort-arrow-down.is-on {
|
|
362
|
+
color: var(--n-color-primary);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.n-dt-th.is-sortable:hover .n-dt-sort-arrow {
|
|
366
|
+
color: var(--n-color-text-muted);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.n-dt-resizer {
|
|
370
|
+
position: absolute;
|
|
371
|
+
right: 0;
|
|
372
|
+
top: 0;
|
|
373
|
+
bottom: 0;
|
|
374
|
+
width: 6px;
|
|
375
|
+
cursor: col-resize;
|
|
376
|
+
background: transparent;
|
|
377
|
+
transition: background 0.15s ease;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.n-dt-resizer:hover {
|
|
381
|
+
background: var(--n-color-primary);
|
|
382
|
+
opacity: 0.4;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.n-dt-filter-row .n-dt-th {
|
|
386
|
+
border-bottom: 1px solid var(--n-color-border);
|
|
387
|
+
padding: 0.5rem 0.6rem;
|
|
388
|
+
background: var(--n-color-surface);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.n-dt-filter {
|
|
392
|
+
width: 100%;
|
|
393
|
+
max-width: 100%;
|
|
394
|
+
display: block;
|
|
395
|
+
background: var(--n-color-bg);
|
|
396
|
+
border: 1px solid var(--n-color-border);
|
|
397
|
+
border-radius: var(--n-radius-sm);
|
|
398
|
+
padding: 0.3rem 0.45rem;
|
|
399
|
+
color: var(--n-color-text);
|
|
400
|
+
font-size: var(--n-text-xs);
|
|
401
|
+
outline: none;
|
|
402
|
+
box-sizing: border-box;
|
|
403
|
+
transition: border-color 0.15s ease;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.n-dt-filter:focus {
|
|
407
|
+
border-color: var(--n-color-primary);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.n-dt-tbody .n-dt-row {
|
|
411
|
+
transition: background 0.15s ease;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.n-dt-tbody .n-dt-row.is-hover:hover {
|
|
415
|
+
background: var(--n-color-glass);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.n-dt-tbody .n-dt-row.is-selected {
|
|
419
|
+
background: var(--n-color-primary-light);
|
|
420
|
+
outline: none;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.n-dt-tbody .n-dt-row.is-hover.is-selected:hover {
|
|
424
|
+
background: var(--n-color-primary-light);
|
|
425
|
+
filter: brightness(0.96);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.n-dt-table.is-striped .n-dt-tbody .n-dt-row:nth-child(even) {
|
|
429
|
+
background: var(--n-color-glass);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.n-dt-table.is-striped .n-dt-tbody .n-dt-row:nth-child(even).is-selected {
|
|
433
|
+
background: var(--n-color-primary-light);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.n-dt-td {
|
|
437
|
+
padding: 0.6rem 0.85rem;
|
|
438
|
+
border-bottom: 1px solid var(--n-color-border);
|
|
439
|
+
color: var(--n-color-text);
|
|
440
|
+
font-size: var(--n-text-sm);
|
|
441
|
+
vertical-align: middle;
|
|
442
|
+
text-align: left;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.n-dt-td.is-right {
|
|
446
|
+
text-align: right;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.n-dt-td.is-center {
|
|
450
|
+
text-align: center;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.n-dt-td.is-selection {
|
|
454
|
+
width: 3rem;
|
|
455
|
+
text-align: center;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.n-dt-selectbox {
|
|
459
|
+
width: 20px;
|
|
460
|
+
height: 20px;
|
|
461
|
+
border: 2px solid var(--n-color-border);
|
|
462
|
+
border-radius: var(--n-radius-sm);
|
|
463
|
+
background: transparent;
|
|
464
|
+
cursor: pointer;
|
|
465
|
+
display: inline-flex;
|
|
466
|
+
align-items: center;
|
|
467
|
+
justify-content: center;
|
|
468
|
+
padding: 0;
|
|
469
|
+
transition: all 0.15s ease;
|
|
470
|
+
color: transparent;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.n-dt-selectbox.is-checked {
|
|
474
|
+
background: var(--n-color-primary);
|
|
475
|
+
border-color: var(--n-color-primary);
|
|
476
|
+
color: white;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.n-dt-selectbox:hover:not(.is-checked) {
|
|
480
|
+
border-color: var(--n-color-primary);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.n-dt-selectbox svg {
|
|
484
|
+
display: block;
|
|
485
|
+
opacity: 0;
|
|
486
|
+
transition: opacity 0.1s ease;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.n-dt-selectbox.is-checked svg {
|
|
490
|
+
opacity: 1;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.n-dt-empty-row .n-dt-empty {
|
|
494
|
+
padding: 2rem 1rem;
|
|
495
|
+
text-align: center;
|
|
496
|
+
color: var(--n-color-text-muted);
|
|
497
|
+
font-size: var(--n-text-sm);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.n-dt-sm .n-dt-th,
|
|
501
|
+
.n-dt-sm .n-dt-td {
|
|
502
|
+
padding: 0.4rem 0.6rem;
|
|
503
|
+
font-size: var(--n-text-xs);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.n-dt-lg .n-dt-th,
|
|
507
|
+
.n-dt-lg .n-dt-td {
|
|
508
|
+
padding: 0.85rem 1rem;
|
|
509
|
+
font-size: var(--n-text-base);
|
|
510
|
+
}
|
|
511
|
+
</style>
|
|
@@ -196,15 +196,15 @@ onBeforeUnmount(() => {
|
|
|
196
196
|
:disabled="disabled"
|
|
197
197
|
readonly
|
|
198
198
|
/>
|
|
199
|
-
<span class="n-datepicker-icon"
|
|
199
|
+
<span class="n-datepicker-icon"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></span>
|
|
200
200
|
</div>
|
|
201
201
|
|
|
202
202
|
<Teleport to="body">
|
|
203
203
|
<div v-if="isOpen.value" class="n-datepicker-dropdown" :class="{ 'is-top': resolvedPlacement.value === 'top' }" :data-datepicker-popup="instanceId" :style="popupStyle.value">
|
|
204
204
|
<div class="n-datepicker-header">
|
|
205
|
-
<button type="button" class="n-datepicker-nav" @click="prevMonth"
|
|
205
|
+
<button type="button" class="n-datepicker-nav" @click="prevMonth" aria-label="Previous month"><svg 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="M15 18l-6-6 6-6"/></svg></button>
|
|
206
206
|
<span class="n-datepicker-title">{{ monthNames[month.value] }} {{ year.value }}</span>
|
|
207
|
-
<button type="button" class="n-datepicker-nav" @click="nextMonth"
|
|
207
|
+
<button type="button" class="n-datepicker-nav" @click="nextMonth" aria-label="Next month"><svg 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="M9 18l6-6-6-6"/></svg></button>
|
|
208
208
|
</div>
|
|
209
209
|
|
|
210
210
|
<div class="n-datepicker-grid">
|
|
@@ -141,9 +141,10 @@ const togglePassword = () => {
|
|
|
141
141
|
/>
|
|
142
142
|
<div class="n-input-focus-ring"></div>
|
|
143
143
|
<div class="n-input-actions">
|
|
144
|
-
<button v-if="clearable && draft.value" class="n-input-action" @click="clear" tabindex="-1" type="button"
|
|
145
|
-
<button v-if="type === 'password'" class="n-input-action" @click="togglePassword" tabindex="-1" type="button">
|
|
146
|
-
|
|
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>
|
|
147
148
|
</button>
|
|
148
149
|
<span v-if="suffixIcon" class="n-input-icon is-suffix">{{ suffixIcon }}</span>
|
|
149
150
|
</div>
|
|
@@ -220,9 +220,9 @@ const onFocus = () => {
|
|
|
220
220
|
<div class="n-inum">
|
|
221
221
|
<label v-if="label" class="n-inum-label">{{ label }}</label>
|
|
222
222
|
<div class="n-inum-wrap" :class="{ 'is-disabled': effectiveDisabled.value }">
|
|
223
|
-
<button type="button" class="n-inum-btn n-inum-dec" :disabled="effectiveDisabled.value || readonly" aria-label="Decrement" @click="dec"
|
|
223
|
+
<button type="button" class="n-inum-btn n-inum-dec" :disabled="effectiveDisabled.value || readonly" aria-label="Decrement" @click="dec"><svg 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"><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
|
|
224
224
|
<input class="n-inum-input" type="text" :value="displayText.value" :placeholder="placeholder" :disabled="effectiveDisabled.value" :readonly="readonly" inputmode="decimal" autocomplete="off" @beforeinput="onBeforeInput" @keydown="onKeydown" @paste="onPaste" @input="onInput" @focus="onFocus" @blur="onBlur" />
|
|
225
|
-
<button type="button" class="n-inum-btn n-inum-inc" :disabled="effectiveDisabled.value || readonly" aria-label="Increment" @click="inc"
|
|
225
|
+
<button type="button" class="n-inum-btn n-inum-inc" :disabled="effectiveDisabled.value || readonly" aria-label="Increment" @click="inc"><svg 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"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
|
|
226
226
|
</div>
|
|
227
227
|
</div>
|
|
228
228
|
</template>
|
|
@@ -100,11 +100,11 @@ onUnmounted(() => {
|
|
|
100
100
|
@keydown="handleKeydown"
|
|
101
101
|
>
|
|
102
102
|
<div v-if="title || $slots.header" class="n-modal-header" :class="{ 'close-left': closeLeft }">
|
|
103
|
-
<button v-if="closable && closeLeft" class="n-modal-close" @click="close" aria-label="Close"
|
|
103
|
+
<button v-if="closable && closeLeft" class="n-modal-close" @click="close" aria-label="Close"><svg viewBox="0 0 24 24" width="20" height="20" 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>
|
|
104
104
|
<slot name="header">
|
|
105
105
|
<h3>{{ title }}</h3>
|
|
106
106
|
</slot>
|
|
107
|
-
<button v-if="closable && !closeLeft" class="n-modal-close" @click="close" aria-label="Close"
|
|
107
|
+
<button v-if="closable && !closeLeft" class="n-modal-close" @click="close" aria-label="Close"><svg viewBox="0 0 24 24" width="20" height="20" 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>
|
|
108
108
|
</div>
|
|
109
109
|
<div class="n-modal-content">
|
|
110
110
|
<slot />
|
|
@@ -155,7 +155,7 @@ onUnmounted(() => {
|
|
|
155
155
|
box-shadow: var(--n-shadow-xl);
|
|
156
156
|
transform: scale(0.9) translateY(20px);
|
|
157
157
|
opacity: 0;
|
|
158
|
-
transition: all
|
|
158
|
+
transition: all var(--n-transition-spring);
|
|
159
159
|
overflow: hidden;
|
|
160
160
|
outline: none;
|
|
161
161
|
max-height: 85vh;
|
|
@@ -216,7 +216,7 @@ onUnmounted(() => {
|
|
|
216
216
|
|
|
217
217
|
.n-modal-footer {
|
|
218
218
|
padding: var(--n-space-5) var(--n-space-8);
|
|
219
|
-
background:
|
|
219
|
+
background: var(--n-color-glass);
|
|
220
220
|
border-top: 1px solid var(--n-color-border);
|
|
221
221
|
display: flex;
|
|
222
222
|
justify-content: flex-end;
|
|
@@ -65,10 +65,10 @@ onBeforeUnmount(() => close())
|
|
|
65
65
|
<div class="n-ms-trigger" role="combobox" tabindex="0" :aria-expanded="isOpen.value" @click="toggleOpen" @keydown="onKeydown">
|
|
66
66
|
<div v-if="selectedLabels.value.length > 0" class="n-ms-chips"><div v-for="c in selectedLabels.value.slice(0, maxChips)" :key="String(c.value)" class="n-ms-chip"><span class="n-ms-chip-label">{{ c.label }}</span><button type="button" class="n-ms-chip-remove" aria-label="Remove" tabindex="-1" :disabled="effectiveDisabled.value" @click="removeChip(c.value, $event)">✕</button></div><span v-if="selectedLabels.value.length > maxChips" class="n-ms-more">+{{ selectedLabels.value.length - maxChips }}</span></div>
|
|
67
67
|
<span v-else class="n-ms-placeholder">{{ placeholder }}</span>
|
|
68
|
-
<div class="n-ms-actions"><button v-if="clearable && selectedLabels.value.length > 0" type="button" class="n-ms-clear" tabindex="-1" @click.stop="clear"
|
|
68
|
+
<div class="n-ms-actions"><button v-if="clearable && selectedLabels.value.length > 0" type="button" class="n-ms-clear" tabindex="-1" @click.stop="clear" 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><span class="n-ms-arrow"><svg 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="M6 9l6 6 6-6"/></svg></span></div>
|
|
69
69
|
</div>
|
|
70
|
-
<div v-if="isOpen.value && appendTo !== 'body'" class="n-ms-dropdown"><div v-if="searchable" class="n-ms-search"><input class="n-ms-search-input" :value="queryDraft.value" placeholder="Search..." @input="onSearchInput" @keydown.stop="onKeydown" /></div><div class="n-ms-options"><button v-for="(opt, i) in filteredOptions.value" :key="String(opt.value) + ':' + i" type="button" class="n-ms-option" :data-ms-opt="String(opt.value)" :class="{ 'is-selected': selectedSet.value.has(opt.value), 'is-focused': i === focusedIndex.value, 'is-disabled': opt.disabled }" :disabled="opt.disabled" @mouseenter="focusedIndex.value = i" @click="toggleValue(opt.value)"><span class="n-ms-check"
|
|
71
|
-
<Teleport to="body"><div v-if="isOpen.value && appendTo === 'body'" class="n-ms-dropdown" :class="{ 'is-top': resolvedPlacement.value === 'top' }" :data-ms-popup="instanceId" :style="popupStyle.value"><div v-if="searchable" class="n-ms-search"><input class="n-ms-search-input" :value="queryDraft.value" placeholder="Search..." @input="onSearchInput" @keydown.stop="onKeydown" /></div><div class="n-ms-options"><button v-for="(opt, i) in filteredOptions.value" :key="String(opt.value) + ':' + i" type="button" class="n-ms-option" :data-ms-opt="String(opt.value)" :class="{ 'is-selected': selectedSet.value.has(opt.value), 'is-focused': i === focusedIndex.value, 'is-disabled': opt.disabled }" :disabled="opt.disabled" @mouseenter="focusedIndex.value = i" @click="toggleValue(opt.value)"><span class="n-ms-check"
|
|
70
|
+
<div v-if="isOpen.value && appendTo !== 'body'" class="n-ms-dropdown"><div v-if="searchable" class="n-ms-search"><input class="n-ms-search-input" :value="queryDraft.value" placeholder="Search..." @input="onSearchInput" @keydown.stop="onKeydown" /></div><div class="n-ms-options"><button v-for="(opt, i) in filteredOptions.value" :key="String(opt.value) + ':' + i" type="button" class="n-ms-option" :data-ms-opt="String(opt.value)" :class="{ 'is-selected': selectedSet.value.has(opt.value), 'is-focused': i === focusedIndex.value, 'is-disabled': opt.disabled }" :disabled="opt.disabled" @mouseenter="focusedIndex.value = i" @click="toggleValue(opt.value)"><span class="n-ms-check"><svg v-if="selectedSet.value.has(opt.value)" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg></span><span class="n-ms-option-label">{{ opt.label }}</span></button><div v-if="filteredOptions.value.length === 0" class="n-ms-empty">No options</div></div></div>
|
|
71
|
+
<Teleport to="body"><div v-if="isOpen.value && appendTo === 'body'" class="n-ms-dropdown" :class="{ 'is-top': resolvedPlacement.value === 'top' }" :data-ms-popup="instanceId" :style="popupStyle.value"><div v-if="searchable" class="n-ms-search"><input class="n-ms-search-input" :value="queryDraft.value" placeholder="Search..." @input="onSearchInput" @keydown.stop="onKeydown" /></div><div class="n-ms-options"><button v-for="(opt, i) in filteredOptions.value" :key="String(opt.value) + ':' + i" type="button" class="n-ms-option" :data-ms-opt="String(opt.value)" :class="{ 'is-selected': selectedSet.value.has(opt.value), 'is-focused': i === focusedIndex.value, 'is-disabled': opt.disabled }" :disabled="opt.disabled" @mouseenter="focusedIndex.value = i" @click="toggleValue(opt.value)"><span class="n-ms-check"><svg v-if="selectedSet.value.has(opt.value)" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" focusable="false" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg></span><span class="n-ms-option-label">{{ opt.label }}</span></button><div v-if="filteredOptions.value.length === 0" class="n-ms-empty">No options</div></div></div></Teleport>
|
|
72
72
|
</div>
|
|
73
73
|
</template>
|
|
74
74
|
|
|
@@ -58,11 +58,11 @@ const end = computed(() => Math.min((safeFirst.value || 0) + (safeRows.value ||
|
|
|
58
58
|
<span class="n-paginator-report">{{ start.value }}-{{ end.value }} of {{ totalRecords }}</span>
|
|
59
59
|
</div>
|
|
60
60
|
<div class="n-paginator-center">
|
|
61
|
-
<button type="button" class="n-pg-btn" :disabled="!canPrev.value" @click="firstPage"
|
|
62
|
-
<button type="button" class="n-pg-btn" :disabled="!canPrev.value" @click="prev"
|
|
61
|
+
<button type="button" class="n-pg-btn" :disabled="!canPrev.value" @click="firstPage" aria-label="First page"><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="M11 17l-5-5 5-5M18 17l-5-5 5-5"/></svg></button>
|
|
62
|
+
<button type="button" class="n-pg-btn" :disabled="!canPrev.value" @click="prev" aria-label="Previous page"><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="M15 18l-6-6 6-6"/></svg></button>
|
|
63
63
|
<span class="n-pg-page">{{ page.value + 1 }} / {{ pageCount.value }}</span>
|
|
64
|
-
<button type="button" class="n-pg-btn" :disabled="!canNext.value" @click="next"
|
|
65
|
-
<button type="button" class="n-pg-btn" :disabled="!canNext.value" @click="lastPage"
|
|
64
|
+
<button type="button" class="n-pg-btn" :disabled="!canNext.value" @click="next" aria-label="Next page"><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="M9 18l6-6-6-6"/></svg></button>
|
|
65
|
+
<button type="button" class="n-pg-btn" :disabled="!canNext.value" @click="lastPage" aria-label="Last page"><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="M13 17l5-5-5-5M6 17l5-5-5-5"/></svg></button>
|
|
66
66
|
</div>
|
|
67
67
|
<div class="n-paginator-right">
|
|
68
68
|
<select class="n-pg-select" :value="rows" @change="changeRows">
|