nexa-ui-kit 0.10.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.
Files changed (73) hide show
  1. package/dist/components/NAlert.js +49 -28
  2. package/dist/components/NAlert.nexa +12 -6
  3. package/dist/components/NAutocomplete.js +25 -20
  4. package/dist/components/NAutocomplete.nexa +3 -3
  5. package/dist/components/NAvatar.js +1 -1
  6. package/dist/components/NBadge.js +1 -1
  7. package/dist/components/NBottomSheet.js +17 -17
  8. package/dist/components/NBottomSheet.nexa +2 -2
  9. package/dist/components/NButton.js +59 -59
  10. package/dist/components/NButton.nexa +10 -9
  11. package/dist/components/NCard.js +2 -2
  12. package/dist/components/NCard.nexa +1 -1
  13. package/dist/components/NCheckbox.js +23 -19
  14. package/dist/components/NCheckbox.nexa +2 -1
  15. package/dist/components/NChips.js +13 -10
  16. package/dist/components/NChips.nexa +1 -1
  17. package/dist/components/NDataTable.js +360 -42
  18. package/dist/components/NDataTable.nexa +318 -10
  19. package/dist/components/NDatepicker.js +52 -43
  20. package/dist/components/NDatepicker.nexa +3 -3
  21. package/dist/components/NForm.js +1 -1
  22. package/dist/components/NFormField.js +1 -1
  23. package/dist/components/NInput.js +51 -41
  24. package/dist/components/NInput.nexa +4 -3
  25. package/dist/components/NInputNumber.js +18 -13
  26. package/dist/components/NInputNumber.nexa +2 -2
  27. package/dist/components/NModal.js +34 -28
  28. package/dist/components/NModal.nexa +4 -4
  29. package/dist/components/NMultiSelect.js +47 -38
  30. package/dist/components/NMultiSelect.nexa +3 -3
  31. package/dist/components/NPaginator.js +29 -21
  32. package/dist/components/NPaginator.nexa +4 -4
  33. package/dist/components/NPassword.js +61 -47
  34. package/dist/components/NPassword.nexa +5 -4
  35. package/dist/components/NProgressBar.js +5 -5
  36. package/dist/components/NProgressBar.nexa +4 -4
  37. package/dist/components/NRadio.js +1 -1
  38. package/dist/components/NScrollView.js +1 -1
  39. package/dist/components/NSelect.js +68 -63
  40. package/dist/components/NSelect.nexa +4 -4
  41. package/dist/components/NSkeleton.js +1 -1
  42. package/dist/components/NSwitch.js +1 -1
  43. package/dist/components/NTabs.js +1 -1
  44. package/dist/components/NTag.js +27 -24
  45. package/dist/components/NTag.nexa +6 -6
  46. package/dist/components/NToastContainer.js +65 -49
  47. package/dist/components/NToastContainer.nexa +6 -3
  48. package/dist/components/NTooltip.js +1 -1
  49. package/dist/components/NTreeMenu.js +24 -22
  50. package/dist/components/NTreeMenu.nexa +1 -1
  51. package/dist/styles/tokens.css +18 -0
  52. package/package.json +4 -4
  53. package/src/components/NAlert.nexa +12 -6
  54. package/src/components/NAutocomplete.nexa +3 -3
  55. package/src/components/NBottomSheet.nexa +2 -2
  56. package/src/components/NButton.nexa +10 -9
  57. package/src/components/NCard.nexa +1 -1
  58. package/src/components/NCheckbox.nexa +2 -1
  59. package/src/components/NChips.nexa +1 -1
  60. package/src/components/NDataTable.nexa +318 -10
  61. package/src/components/NDatepicker.nexa +3 -3
  62. package/src/components/NInput.nexa +4 -3
  63. package/src/components/NInputNumber.nexa +2 -2
  64. package/src/components/NModal.nexa +4 -4
  65. package/src/components/NMultiSelect.nexa +3 -3
  66. package/src/components/NPaginator.nexa +4 -4
  67. package/src/components/NPassword.nexa +5 -4
  68. package/src/components/NProgressBar.nexa +4 -4
  69. package/src/components/NSelect.nexa +4 -4
  70. package/src/components/NTag.nexa +6 -6
  71. package/src/components/NToastContainer.nexa +6 -3
  72. package/src/components/NTreeMenu.nexa +1 -1
  73. package/src/styles/tokens.css +18 -0
@@ -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
- <div class="n-dt" :class="[`n-dt-${size}`, showGridlines ? 'is-grid' : '', scrollable ? 'is-scroll' : '']">
167
- <div class="n-dt-toolbar"><div class="n-dt-global"><input class="n-dt-global-input" :value="effectiveFilters.value.__global || ''" placeholder="Search..." @input="setGlobal" /></div></div>
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"><input v-if="selectionMode === 'multiple'" class="n-dt-selectbox" type="checkbox" :checked="allVisibleSelected.value" @click.stop="toggleAllVisible" /></th>
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
- <span v-if="internalSortField.value !== col.field" class="n-dt-sort-icon">↕</span>
178
- <span v-else class="n-dt-sort-icon">{{ internalSortOrder.value === 1 ? '↑' : '↓' }}</span>
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"><th v-if="selectionMode" class="n-dt-th is-selection"></th><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 }"><input v-if="col.filterable" class="n-dt-filter" :data-field="col.field" :value="(effectiveFilters.value[col.field]?.value) || ''" placeholder="Filter" @input="onColumnFilterInput" /></th></tr>
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"><input class="n-dt-selectbox" type="checkbox" :checked="isRowSelected(row, i + internalFirst.value)" @click.stop="toggleRowSelection(row, i + internalFirst.value)" /></td>
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{border:1px solid var(--n-color-border);border-radius:var(--n-radius-lg);background:var(--n-color-surface);overflow:hidden;font-family:var(--n-font-sans)}.n-dt-toolbar{display:flex;align-items:center;justify-content:space-between;padding:var(--n-space-3) var(--n-space-4);border-bottom:1px solid var(--n-color-border);background:linear-gradient(180deg,rgba(255,255,255,.04),rgba(0,0,0,.08))}.n-dt-global{display:flex;align-items:center;gap:var(--n-space-2)}.n-dt-global-input{width:280px;max-width:100%;background:var(--n-color-bg);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);padding:0.55rem 0.75rem;color:var(--n-color-text);font-size:var(--n-text-sm);outline:none;box-sizing:border-box}.n-dt-global-input:focus{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-dt-wrapper{width:100%;overflow:auto}.n-dt-table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.n-dt-thead{background:var(--n-color-surface)}.n-dt-th,.n-dt-td{padding:0.75rem 0.9rem;border-bottom:1px solid var(--n-color-border);color:var(--n-color-text);font-size:var(--n-text-sm);vertical-align:middle}.n-dt-th{position:relative;overflow:hidden;background:rgba(0,0,0,.10);color:var(--n-color-text-secondary);font-weight:var(--n-weight-semibold);user-select:none}.n-dt-th.is-sortable{cursor:pointer}.n-dt-th-content{display:flex;align-items:center;justify-content:space-between;gap:0.5rem}.n-dt-sort{display:inline-flex;align-items:center;gap:0.25rem;color:var(--n-color-text-muted)}.n-dt-sort.is-active{color:var(--n-color-primary)}.n-dt-resizer{position:absolute;right:0;top:0;bottom:0;width:8px;cursor:col-resize}.n-dt-filter-row .n-dt-th{background:rgba(0,0,0,.06)}.n-dt-filter{width:100%;max-width:100%;display:block;background:var(--n-color-bg);border:1px solid var(--n-color-border);border-radius:var(--n-radius-sm);padding:0.35rem 0.5rem;color:var(--n-color-text);font-size:var(--n-text-xs);outline:none;box-sizing:border-box}.n-dt-filter:focus{border-color:var(--n-color-primary)}.n-dt-td{background:transparent;color:var(--n-color-text)}.n-dt-row.is-selected .n-dt-td{background:rgba(59,130,246,.12)}.n-dt-table.is-striped .n-dt-row:nth-child(even) .n-dt-td{background:rgba(0,0,0,.06)}.n-dt-table.is-hover .n-dt-row:hover .n-dt-td{background:rgba(255,255,255,.06)}.n-dt-empty{text-align:center;color:var(--n-color-text-muted);padding:1.25rem}.is-left{text-align:left}.is-right{text-align:right}.is-center{text-align:center}.is-selection{width:44px;min-width:44px;max-width:44px;text-align:center}.n-dt-selectbox{width:16px;height:16px;accent-color:var(--n-color-primary)}.n-dt-check{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:4px;border:1px solid var(--n-color-border);color:var(--n-color-primary)}.is-grid .n-dt-td,.is-grid .n-dt-th{border-right:1px solid var(--n-color-border)}.is-grid .n-dt-td:last-child,.is-grid .n-dt-th:last-child{border-right:none}.n-dt-sm .n-dt-th,.n-dt-sm .n-dt-td{padding:0.55rem 0.7rem}.n-dt-lg .n-dt-th,.n-dt-lg .n-dt-td{padding:0.9rem 1rem}
203
- </style>
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>
@@ -1,9 +1,9 @@
1
- import { signal, computed, onBeforeUnmount, h, hText, effect, onMounted, onUnmounted, defineComponent, registerComponent, reloadComponent, injectStyle, Teleport } from 'nexa-framework'
1
+ import { signal, computed, onBeforeUnmount, h, hText, effect, defineComponent, registerComponent, reloadComponent, injectStyle, Teleport } from 'nexa-framework'
2
2
  import NInput from './NInput.js'
3
3
  import { trackFloatingOverlay } from '../services/FloatingOverlay.js'
4
4
 
5
5
  const _sfc_main = defineComponent({
6
- __scopeId: 'data-v-69fa2c78',
6
+ __scopeId: 'data-v-7501a13d',
7
7
  __hmrId: 'NDatepicker_nexa',
8
8
  props: {
9
9
  modelValue: { type: String, default: '' },
@@ -174,44 +174,53 @@ const _sfc_main = defineComponent({
174
174
  // Injected render function
175
175
  _sfc_main.render = function(ctx) {
176
176
  let { isOpen, viewDate, instanceId, popupStyle, resolvedPlacement, stopTracking, today, year, month, daysInMonth, firstDayOfWeek, calendarDays, formatDate, parseDate, minDate, maxDate, isDisabled, closePopup, syncViewDateFromModel, selectDate, prevMonth, nextMonth, monthNames, dayNames, isSelected, isToday, closeHandler, rootEl, openPopup, onBeforeUnmount, NInput: _ntc_NInput, trackFloatingOverlay, $slots, emit, modelValue, placeholder, disabled, min, max, placement, Fragment: _ntc_Fragment, Teleport: _ntc_Teleport } = ctx
177
- return h('div', { class: "n-datepicker", "data-datepicker-root": instanceId, "data-v-69fa2c78": "" }, [
177
+ return h('div', { class: "n-datepicker", "data-datepicker-root": instanceId, "data-v-7501a13d": "" }, [
178
178
  "\n ",
179
- h('div', { class: "n-datepicker-input", onClick: openPopup, "data-v-69fa2c78": "" }, [
179
+ h('div', { class: "n-datepicker-input", onClick: openPopup, "data-v-7501a13d": "" }, [
180
180
  "\n ",
181
- h(_ntc_NInput, { modelValue: modelValue, placeholder: placeholder, disabled: disabled, readonly: true, "data-v-69fa2c78": "" }),
181
+ h(_ntc_NInput, { modelValue: modelValue, placeholder: placeholder, disabled: disabled, readonly: true, "data-v-7501a13d": "" }),
182
182
  "\n ",
183
- h('span', { class: "n-datepicker-icon", "data-v-69fa2c78": "" }, [
184
- "📅"
183
+ h('span', { class: "n-datepicker-icon", "data-v-7501a13d": "" }, [
184
+ h('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", "data-v-7501a13d": "" }, [
185
+ h('rect', { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2", "data-v-7501a13d": "" }),
186
+ h('line', { x1: "16", y1: "2", x2: "16", y2: "6", "data-v-7501a13d": "" }),
187
+ h('line', { x1: "8", y1: "2", x2: "8", y2: "6", "data-v-7501a13d": "" }),
188
+ h('line', { x1: "3", y1: "10", x2: "21", y2: "10", "data-v-7501a13d": "" })
189
+ ])
185
190
  ]),
186
191
  "\n "
187
192
  ]),
188
193
  "\n\n ",
189
- h(_ntc_Teleport, { to: "body", "data-v-69fa2c78": "" }, [
194
+ h(_ntc_Teleport, { to: "body", "data-v-7501a13d": "" }, [
190
195
  "\n ",
191
- (isOpen.value) ? h('div', { class: ["n-datepicker-dropdown", { 'is-top': resolvedPlacement.value === 'top' }], "data-datepicker-popup": instanceId, style: popupStyle.value, "data-v-69fa2c78": "" }, [
196
+ (isOpen.value) ? h('div', { class: ["n-datepicker-dropdown", { 'is-top': resolvedPlacement.value === 'top' }], "data-datepicker-popup": instanceId, style: popupStyle.value, "data-v-7501a13d": "" }, [
192
197
  "\n ",
193
- h('div', { class: "n-datepicker-header", "data-v-69fa2c78": "" }, [
198
+ h('div', { class: "n-datepicker-header", "data-v-7501a13d": "" }, [
194
199
  "\n ",
195
- h('button', { class: "n-datepicker-nav", type: "button", onClick: prevMonth, "data-v-69fa2c78": "" }, [
196
- ""
200
+ h('button', { class: "n-datepicker-nav", type: "button", onClick: prevMonth, "aria-label": "Previous month", "data-v-7501a13d": "" }, [
201
+ h('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", "data-v-7501a13d": "" }, [
202
+ h('path', { d: "M15 18l-6-6 6-6", "data-v-7501a13d": "" })
203
+ ])
197
204
  ]),
198
205
  "\n ",
199
- h('span', { class: "n-datepicker-title", "data-v-69fa2c78": "" }, [
206
+ h('span', { class: "n-datepicker-title", "data-v-7501a13d": "" }, [
200
207
  monthNames[month.value],
201
208
  " ",
202
209
  year.value
203
210
  ]),
204
211
  "\n ",
205
- h('button', { class: "n-datepicker-nav", type: "button", onClick: nextMonth, "data-v-69fa2c78": "" }, [
206
- ""
212
+ h('button', { class: "n-datepicker-nav", type: "button", onClick: nextMonth, "aria-label": "Next month", "data-v-7501a13d": "" }, [
213
+ h('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", "data-v-7501a13d": "" }, [
214
+ h('path', { d: "M9 18l6-6-6-6", "data-v-7501a13d": "" })
215
+ ])
207
216
  ]),
208
217
  "\n "
209
218
  ]),
210
219
  "\n\n ",
211
- h('div', { class: "n-datepicker-grid", "data-v-69fa2c78": "" }, [
220
+ h('div', { class: "n-datepicker-grid", "data-v-7501a13d": "" }, [
212
221
  "\n ",
213
222
  (dayNames).map((d, index) =>
214
- h('div', { class: "n-datepicker-day-header", key: d, "data-v-69fa2c78": "" }, [
223
+ h('div', { class: "n-datepicker-day-header", key: d, "data-v-7501a13d": "" }, [
215
224
  d
216
225
  ])
217
226
  ),
@@ -223,7 +232,7 @@ _sfc_main.render = function(ctx) {
223
232
  'is-disabled': day !== null && isDisabled(day),
224
233
  'is-selected': day !== null && isSelected(day),
225
234
  'is-today': day !== null && isToday(day)
226
- }, key: i, onClick: ($event) => { selectDate(day) }, "data-v-69fa2c78": "" }, [
235
+ }, key: i, onClick: ($event) => { selectDate(day) }, "data-v-7501a13d": "" }, [
227
236
  day ?? ''
228
237
  ])
229
238
  ),
@@ -235,27 +244,27 @@ _sfc_main.render = function(ctx) {
235
244
  "\n "
236
245
  ])
237
246
  }
238
- _sfc_main.__scopeId = 'data-v-69fa2c78'
247
+ _sfc_main.__scopeId = 'data-v-7501a13d'
239
248
  _sfc_main.__hmrId = 'NDatepicker_nexa'
240
249
 
241
250
  export default _sfc_main
242
251
 
243
- const __style = `.n-datepicker[data-v-69fa2c78]{
252
+ const __style = `.n-datepicker[data-v-7501a13d]{
244
253
  position: relative;
245
254
  display: inline-block;
246
255
  font-family: var(--n-font-sans);
247
256
  }
248
257
 
249
- .n-datepicker-input[data-v-69fa2c78]{
258
+ .n-datepicker-input[data-v-7501a13d]{
250
259
  position: relative;
251
260
  cursor: pointer;
252
261
  }
253
262
 
254
- .n-datepicker-input .n-input[data-v-69fa2c78]{
263
+ .n-datepicker-input .n-input[data-v-7501a13d]{
255
264
  cursor: pointer;
256
265
  }
257
266
 
258
- .n-datepicker-icon[data-v-69fa2c78]{
267
+ .n-datepicker-icon[data-v-7501a13d]{
259
268
  position: absolute;
260
269
  right: 0.75rem;
261
270
  top: 50%;
@@ -264,7 +273,7 @@ const __style = `.n-datepicker[data-v-69fa2c78]{
264
273
  pointer-events: none;
265
274
  }
266
275
 
267
- .n-datepicker-dropdown[data-v-69fa2c78]{
276
+ .n-datepicker-dropdown[data-v-7501a13d]{
268
277
  position: absolute;
269
278
  top: calc(100% + 4px);
270
279
  left: 0;
@@ -279,33 +288,33 @@ const __style = `.n-datepicker[data-v-69fa2c78]{
279
288
  }
280
289
 
281
290
  @keyframes fade-in {
282
- from[data-v-69fa2c78]{ opacity: 0; transform: translateY(-4px); }
283
- to[data-v-69fa2c78]{ opacity: 1; transform: translateY(0); }
291
+ from[data-v-7501a13d]{ opacity: 0; transform: translateY(-4px); }
292
+ to[data-v-7501a13d]{ opacity: 1; transform: translateY(0); }
284
293
  }
285
294
 
286
- .n-datepicker-dropdown.is-top[data-v-69fa2c78]{
295
+ .n-datepicker-dropdown.is-top[data-v-7501a13d]{
287
296
  animation: fade-in-top 0.15s ease;
288
297
  }
289
298
 
290
299
  @keyframes fade-in-top {
291
- from[data-v-69fa2c78]{ opacity: 0; transform: translateY(4px); }
292
- to[data-v-69fa2c78]{ opacity: 1; transform: translateY(0); }
300
+ from[data-v-7501a13d]{ opacity: 0; transform: translateY(4px); }
301
+ to[data-v-7501a13d]{ opacity: 1; transform: translateY(0); }
293
302
  }
294
303
 
295
- .n-datepicker-header[data-v-69fa2c78]{
304
+ .n-datepicker-header[data-v-7501a13d]{
296
305
  display: flex;
297
306
  align-items: center;
298
307
  justify-content: space-between;
299
308
  margin-bottom: 0.75rem;
300
309
  }
301
310
 
302
- .n-datepicker-title[data-v-69fa2c78]{
311
+ .n-datepicker-title[data-v-7501a13d]{
303
312
  font-weight: var(--n-weight-semibold);
304
313
  font-size: var(--n-text-sm);
305
314
  color: var(--n-color-text);
306
315
  }
307
316
 
308
- .n-datepicker-nav[data-v-69fa2c78]{
317
+ .n-datepicker-nav[data-v-7501a13d]{
309
318
  background: none;
310
319
  border: 1px solid var(--n-color-border);
311
320
  color: var(--n-color-text-secondary);
@@ -320,18 +329,18 @@ to[data-v-69fa2c78]{ opacity: 1; transform: translateY(0); }
320
329
  transition: all var(--n-transition-fast);
321
330
  }
322
331
 
323
- .n-datepicker-nav[data-v-69fa2c78]:hover{
332
+ .n-datepicker-nav[data-v-7501a13d]:hover{
324
333
  background: var(--n-color-surface-hover);
325
334
  color: var(--n-color-text);
326
335
  }
327
336
 
328
- .n-datepicker-grid[data-v-69fa2c78]{
337
+ .n-datepicker-grid[data-v-7501a13d]{
329
338
  display: grid;
330
339
  grid-template-columns: repeat(7, 1fr);
331
340
  gap: 2px;
332
341
  }
333
342
 
334
- .n-datepicker-day-header[data-v-69fa2c78]{
343
+ .n-datepicker-day-header[data-v-7501a13d]{
335
344
  text-align: center;
336
345
  font-size: var(--n-text-xs);
337
346
  color: var(--n-color-text-muted);
@@ -339,7 +348,7 @@ to[data-v-69fa2c78]{ opacity: 1; transform: translateY(0); }
339
348
  padding: 0.35rem 0;
340
349
  }
341
350
 
342
- .n-datepicker-day[data-v-69fa2c78]{
351
+ .n-datepicker-day[data-v-7501a13d]{
343
352
  text-align: center;
344
353
  padding: 0.4rem 0;
345
354
  font-size: var(--n-text-sm);
@@ -349,31 +358,31 @@ to[data-v-69fa2c78]{ opacity: 1; transform: translateY(0); }
349
358
  transition: all var(--n-transition-fast);
350
359
  }
351
360
 
352
- .n-datepicker-day[data-v-69fa2c78]:hover:not(.is-empty){
361
+ .n-datepicker-day[data-v-7501a13d]:hover:not(.is-empty){
353
362
  background: var(--n-color-primary-light);
354
363
  }
355
364
 
356
- .n-datepicker-day.is-empty[data-v-69fa2c78]{
365
+ .n-datepicker-day.is-empty[data-v-7501a13d]{
357
366
  cursor: default;
358
367
  }
359
368
 
360
- .n-datepicker-day.is-disabled[data-v-69fa2c78]{
369
+ .n-datepicker-day.is-disabled[data-v-7501a13d]{
361
370
  opacity: 0.4;
362
371
  cursor: not-allowed;
363
372
  }
364
373
 
365
- .n-datepicker-day.is-disabled[data-v-69fa2c78]:hover{
374
+ .n-datepicker-day.is-disabled[data-v-7501a13d]:hover{
366
375
  background: transparent;
367
376
  }
368
377
 
369
- .n-datepicker-day.is-today[data-v-69fa2c78]{
378
+ .n-datepicker-day.is-today[data-v-7501a13d]{
370
379
  font-weight: var(--n-weight-bold);
371
380
  color: var(--n-color-primary);
372
381
  }
373
382
 
374
- .n-datepicker-day.is-selected[data-v-69fa2c78]{
383
+ .n-datepicker-day.is-selected[data-v-7501a13d]{
375
384
  background: var(--n-color-primary);
376
385
  color: white;
377
386
  font-weight: var(--n-weight-semibold);
378
387
  }`
379
- injectStyle('data-v-69fa2c78', __style)
388
+ injectStyle('data-v-7501a13d', __style)
@@ -196,15 +196,15 @@ onBeforeUnmount(() => {
196
196
  :disabled="disabled"
197
197
  readonly
198
198
  />
199
- <span class="n-datepicker-icon">📅</span>
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">‹</button>
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">›</button>
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">
@@ -1,4 +1,4 @@
1
- import { signal, computed, provide, h, hText, effect, onMounted, onUnmounted, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
1
+ import { signal, computed, provide, h, hText, effect, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
2
2
 
3
3
  const _sfc_main = defineComponent({
4
4
  __scopeId: 'data-v-38e99ca2',
@@ -1,4 +1,4 @@
1
- import { signal, computed, inject, provide, effect, onUnmounted, h, hText, onMounted, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
1
+ import { signal, computed, inject, provide, effect, onUnmounted, h, hText, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
2
2
 
3
3
  const _sfc_main = defineComponent({
4
4
  __scopeId: 'data-v-30bdb720',