nexa-ui-kit 0.7.11 → 0.8.1

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.
@@ -1,204 +1,203 @@
1
- <script setup>
2
- import { signal, computed, effect } from 'nexa-framework'
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 } })
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
- const internalFirst = signal(props.first || 0)
7
- const internalRows = signal(props.rows || 10)
8
- const internalSortField = signal(props.sortField || '')
9
- const internalSortOrder = signal(props.sortOrder || 1)
10
- const internalFilters = signal((props.filters && typeof props.filters === 'object') ? props.filters : { __global: props.globalFilter || '' })
11
- const effectiveFilters = computed(() => (props.filters && typeof props.filters === 'object') ? props.filters : internalFilters.value)
12
- const columnWidths = signal({})
13
- const resizing = signal(null)
14
- const internalSelection = signal(props.selection)
15
-
16
- effect(() => { internalFirst.value = props.first || 0 })
17
- effect(() => { internalRows.value = props.rows || 10 })
18
- effect(() => { internalSortField.value = props.sortField || '' })
19
- effect(() => { internalSortOrder.value = props.sortOrder || 1 })
20
- let lastPropGlobal = props.globalFilter || ''
21
- effect(() => {
22
- const next = props.globalFilter || ''
23
- if (next === lastPropGlobal) return
24
- lastPropGlobal = next
25
- if (props.filters && typeof props.filters === 'object') return
26
- internalFilters.value = { ...internalFilters.value, __global: next }
27
- })
28
-
29
- let lastPropSelection = props.selection
30
- effect(() => {
31
- const next = props.selection
32
- if (next === lastPropSelection) return
33
- lastPropSelection = next
34
- internalSelection.value = next
35
- })
36
- const normalizeColumns = computed(() => (props.columns || []).map((c, idx) => { const field = c.field || `col_${idx}`; const header = c.header ?? field; const sortable = !!c.sortable; const filterable = c.filterable !== false; const type = c.type || 'text'; const width = c.width || ''; const minWidth = c.minWidth || '120px'; const align = c.align || (type === 'number' ? 'right' : 'left'); const filterMatchMode = c.filterMatchMode || 'contains'; return { ...c, field, header, sortable, filterable, type, width, minWidth, align, filterMatchMode } }))
37
- const getRowKey = (row, index) => (props.dataKey && row && typeof row === 'object' && props.dataKey in row) ? String(row[props.dataKey]) : String(index)
38
- const effectiveSelection = computed(() => internalSelection.value)
39
- const isRowSelected = (row, index) => {
40
- if (!props.selectionMode) return false
41
- const selection = effectiveSelection.value
42
- const key = getRowKey(row, index)
43
- if (props.selectionMode === 'single') {
44
- if (!selection) return false
45
- if (props.dataKey && typeof selection === 'object' && selection && props.dataKey in selection) return String(selection[props.dataKey]) === key
46
- return selection === row
47
- }
48
- const current = Array.isArray(selection) ? selection : []
49
- if (props.dataKey) return current.some(s => s && typeof s === 'object' && props.dataKey in s && String(s[props.dataKey]) === key)
50
- return current.includes(row)
51
- }
52
- const toggleRowSelection = (row, index) => {
53
- if (!props.selectionMode) return
54
- const selected = isRowSelected(row, index)
55
- if (props.selectionMode === 'single') {
56
- const next = selected ? null : row
57
- internalSelection.value = next
58
- emit('update:selection', next)
59
- emit('updateSelection', next)
60
- emit(selected ? 'rowUnselect' : 'rowSelect', { data: row })
61
- return
62
- }
63
- const current = Array.isArray(effectiveSelection.value) ? effectiveSelection.value : []
64
- const key = getRowKey(row, index)
65
- const next = selected
66
- ? (props.dataKey ? current.filter(r => String(r?.[props.dataKey]) !== key) : current.filter(r => r !== row))
67
- : [...current, row]
68
- internalSelection.value = next
69
- emit('update:selection', next)
70
- emit('updateSelection', next)
71
- emit(selected ? 'rowUnselect' : 'rowSelect', { data: row })
72
- }
73
-
74
- const allVisibleSelected = computed(() => {
75
- if (props.selectionMode !== 'multiple') return false
76
- const rows = visibleRows.value
77
- if (rows.length === 0) return false
78
- for (let i = 0; i < rows.length; i++) {
79
- if (!isRowSelected(rows[i], i + (internalFirst.value || 0))) return false
80
- }
81
- return true
82
- })
83
-
84
- const toggleAllVisible = () => {
85
- if (props.selectionMode !== 'multiple') return
86
- const current = Array.isArray(effectiveSelection.value) ? effectiveSelection.value : []
87
- const rows = visibleRows.value
88
- const startIndex = internalFirst.value || 0
89
- if (rows.length === 0) return
90
- if (allVisibleSelected.value) {
91
- if (!props.dataKey) {
92
- const next = current.filter(r => !rows.includes(r))
93
- internalSelection.value = next
94
- emit('update:selection', next)
95
- emit('updateSelection', next)
96
- return
97
- }
98
- const keys = rows.map((r, i) => getRowKey(r, startIndex + i))
99
- const next = current.filter(r => !keys.includes(String(r?.[props.dataKey])))
100
- internalSelection.value = next
101
- emit('update:selection', next)
102
- emit('updateSelection', next)
103
- return
104
- }
105
- if (!props.dataKey) {
106
- const next = [...current, ...rows.filter(r => !current.includes(r))]
107
- internalSelection.value = next
108
- emit('update:selection', next)
109
- emit('updateSelection', next)
110
- return
111
- }
112
- const existing = new Set(current.map(r => String(r?.[props.dataKey])))
113
- const next = [...current, ...rows.filter((r) => !existing.has(String(r?.[props.dataKey])))]
114
- internalSelection.value = next
115
- emit('update:selection', next)
116
- emit('updateSelection', next)
117
- }
118
- const getHeaderContent = (col) => (col.headerTemplate && typeof col.headerTemplate === 'function') ? col.headerTemplate(col) : col.header
119
- const getRawValue = (row, col) => { if (!row) return ''; if (col.field && typeof row === 'object' && col.field in row) return row[col.field]; return '' }
120
- const getCellContent = (row, col, index) => { const raw = getRawValue(row, col); if (col.body && typeof col.body === 'function') return col.body(row, { index, column: col, field: col.field, value: raw }); return raw }
121
- const matchFilter = (value, query, mode) => { const q = String(query ?? '').toLowerCase().trim(); if (!q) return true; const v = String(value ?? '').toLowerCase(); if (mode === 'equals') return v === q; if (mode === 'startsWith') return v.startsWith(q); if (mode === 'endsWith') return v.endsWith(q); return v.includes(q) }
122
- const filteredRows = computed(() => { const rows = props.value || []; if (props.lazy) return rows; const cols = normalizeColumns.value; const filters = effectiveFilters.value || {}; const global = String(filters.__global || '').trim(); const keys = Object.keys(filters).filter(k => k !== '__global'); if (!global && keys.length === 0) return rows; const globalFields = Array.isArray(props.globalFilterFields) && props.globalFilterFields.length ? props.globalFilterFields : cols.map(c => c.field); return rows.filter((row) => { if (global) { const ok = globalFields.some((f) => matchFilter(getRawValue(row, { field: f }), global, 'contains')); if (!ok) return false } for (const c of cols) { const f = filters[c.field]; if (!f) continue; if (!matchFilter(getRawValue(row, c), f.value, f.matchMode || c.filterMatchMode || 'contains')) return false } return true }) })
123
- const sortedRows = computed(() => { if (props.lazy) return filteredRows.value; const rows = [...filteredRows.value]; const field = internalSortField.value; if (!field) return rows; const col = normalizeColumns.value.find(c => c.field === field); const order = internalSortOrder.value === -1 ? -1 : 1; const type = col?.type || 'text'; rows.sort((a, b) => { const av = getCellContent(a, { field }, -1); const bv = getCellContent(b, { field }, -1); if (type === 'number') return (Number(av) - Number(bv)) * order; return String(av ?? '').localeCompare(String(bv ?? ''), undefined, { numeric: true, sensitivity: 'base' }) * order }); return rows })
124
- const totalRecords = computed(() => props.lazy ? (props.totalRecords || (props.value || []).length) : sortedRows.value.length)
125
- const visibleRows = computed(() => props.lazy ? (props.value || []) : (!props.paginator ? sortedRows.value : sortedRows.value.slice(internalFirst.value || 0, (internalFirst.value || 0) + (internalRows.value || 10))))
126
- const setSort = (col) => {
127
- if (!col.sortable) return
128
- const nextField = col.field
129
- let nextOrder = 1
130
- if (internalSortField.value === nextField) nextOrder = internalSortOrder.value === 1 ? -1 : 1
131
- internalSortField.value = nextField
132
- internalSortOrder.value = nextOrder
133
- internalFirst.value = 0
134
- emit('update:sortField', nextField)
135
- emit('update:sortOrder', nextOrder)
136
- emit('updateSortField', nextField)
137
- emit('updateSortOrder', nextOrder)
138
- emit('sort', { sortField: nextField, sortOrder: nextOrder })
139
- }
140
- const onSortClick = (e) => { const field = e.currentTarget?.dataset?.field; if (!field) return; const col = normalizeColumns.value.find(c => c.field === field); if (!col) return; setSort(col) }
141
- const setGlobal = (e) => {
142
- const next = e.target.value
143
- const nextFilters = { ...(effectiveFilters.value || {}), __global: next }
144
- if (props.filters && typeof props.filters === 'object') { emit('update:filters', nextFilters); emit('updateFilters', nextFilters) } else { internalFilters.value = nextFilters }
145
- internalFirst.value = 0
146
- emit('update:globalFilter', next)
147
- emit('updateGlobalFilter', next)
148
- emit('filter', { global: next, filters: nextFilters })
149
- }
150
- const setColumnFilter = (field, e) => { const next = e.target.value; const current = { ...(effectiveFilters.value || {}) }; const col = normalizeColumns.value.find(c => c.field === field); if (!next) delete current[field]; else current[field] = { value: next, matchMode: col?.filterMatchMode || current[field]?.matchMode || 'contains' }; if (props.filters && typeof props.filters === 'object') { emit('update:filters', current); emit('updateFilters', current) } else { internalFilters.value = current } internalFirst.value = 0; emit('filter', { field, value: next, filters: current }) }
151
- const onColumnFilterInput = (e) => { const field = e.target?.dataset?.field; if (!field) return; setColumnFilter(field, e) }
152
- const onPage = ({ first, rows }) => {
153
- internalFirst.value = first
154
- internalRows.value = rows
155
- emit('update:first', first)
156
- emit('update:rows', rows)
157
- emit('updateFirst', first)
158
- emit('updateRows', rows)
159
- emit('page', { first, rows })
160
- }
161
- const getWidth = (col) => columnWidths.value[col.field] || col.width || ''
162
- const startResize = (e) => { if (!props.resizableColumns) return; const field = e.currentTarget?.dataset?.field; if (!field) return; e.preventDefault(); e.stopPropagation(); const th = e.currentTarget?.parentElement; const base = th?.getBoundingClientRect?.().width || parseFloat(th?.style?.width || '') || 160; resizing.value = { field, startX: e.clientX, startW: base }; const onMove = (ev) => { if (!resizing.value) return; const delta = ev.clientX - resizing.value.startX; const next = Math.max(80, resizing.value.startW + delta); columnWidths.value = { ...columnWidths.value, [resizing.value.field]: `${Math.round(next)}px` } }; const onUp = () => { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); resizing.value = null }; document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp) }
163
- </script>
164
-
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>
168
- <div class="n-dt-wrapper">
169
- <table class="n-dt-table" :class="{ 'is-striped': stripedRows, 'is-hover': hoverRows }">
170
- <thead class="n-dt-thead">
171
- <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>
173
- <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
- <div class="n-dt-th-content">
175
- <span class="n-dt-th-text">{{ $slots.value && $slots.value[`header-${col.field}`] ? $slots[`header-${col.field}`]({ column: col }) : getHeaderContent(col) }}</span>
176
- <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>
179
- </span>
180
- </div>
181
- <span v-if="resizableColumns" class="n-dt-resizer" :data-field="col.field" @mousedown="startResize"></span>
182
- </th>
183
- </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>
185
- </thead>
186
- <tbody class="n-dt-tbody">
187
- <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>
189
- <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
- <span v-if="$slots.value && $slots.value[`body-${col.field}`]">{{ $slots[`body-${col.field}`]({ data: row, column: col, index: i + internalFirst.value }) }}</span>
191
- <span v-else :innerHTML="getCellContent(row, col, i + internalFirst.value)"></span>
192
- </td>
193
- </tr>
194
- <tr v-if="visibleRows.value.length === 0" class="n-dt-empty-row"><td :colspan="normalizeColumns.value.length + (selectionMode ? 1 : 0)" class="n-dt-empty">{{ emptyMessage }}</td></tr>
195
- </tbody>
196
- </table>
197
- </div>
198
- <NPaginator v-if="paginator" :first="internalFirst.value" :rows="internalRows.value" :totalRecords="totalRecords.value" :rowsPerPageOptions="rowsPerPageOptions" @page="onPage" />
199
- </div>
200
- </template>
201
-
202
- <style scoped>
203
- .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}
204
- </style>
1
+ <script setup>
2
+ import { signal, computed, effect } from 'nexa-framework'
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 } })
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
+ const internalFirst = signal(props.first || 0)
7
+ const internalRows = signal(props.rows || 10)
8
+ const internalSortField = signal(props.sortField || '')
9
+ const internalSortOrder = signal(props.sortOrder || 1)
10
+ const internalFilters = signal((props.filters && typeof props.filters === 'object') ? props.filters : { __global: props.globalFilter || '' })
11
+ const effectiveFilters = computed(() => (props.filters && typeof props.filters === 'object') ? props.filters : internalFilters.value)
12
+ const columnWidths = signal({})
13
+ const resizing = signal(null)
14
+ const internalSelection = signal(props.selection)
15
+
16
+ effect(() => { internalFirst.value = props.first || 0 })
17
+ effect(() => { internalRows.value = props.rows || 10 })
18
+ effect(() => { internalSortField.value = props.sortField || '' })
19
+ effect(() => { internalSortOrder.value = props.sortOrder || 1 })
20
+ let lastPropGlobal = props.globalFilter || ''
21
+ effect(() => {
22
+ const next = props.globalFilter || ''
23
+ if (next === lastPropGlobal) return
24
+ lastPropGlobal = next
25
+ if (props.filters && typeof props.filters === 'object') return
26
+ internalFilters.value = { ...internalFilters.value, __global: next }
27
+ })
28
+
29
+ let lastPropSelection = props.selection
30
+ effect(() => {
31
+ const next = props.selection
32
+ if (next === lastPropSelection) return
33
+ lastPropSelection = next
34
+ internalSelection.value = next
35
+ })
36
+ const normalizeColumns = computed(() => (props.columns || []).map((c, idx) => { const field = c.field || `col_${idx}`; const header = c.header ?? field; const sortable = !!c.sortable; const filterable = c.filterable !== false; const type = c.type || 'text'; const width = c.width || ''; const minWidth = c.minWidth || '120px'; const align = c.align || (type === 'number' ? 'right' : 'left'); const filterMatchMode = c.filterMatchMode || 'contains'; return { ...c, field, header, sortable, filterable, type, width, minWidth, align, filterMatchMode } }))
37
+ const getRowKey = (row, index) => (props.dataKey && row && typeof row === 'object' && props.dataKey in row) ? String(row[props.dataKey]) : String(index)
38
+ const effectiveSelection = computed(() => internalSelection.value)
39
+ const isRowSelected = (row, index) => {
40
+ if (!props.selectionMode) return false
41
+ const selection = effectiveSelection.value
42
+ const key = getRowKey(row, index)
43
+ if (props.selectionMode === 'single') {
44
+ if (!selection) return false
45
+ if (props.dataKey && typeof selection === 'object' && selection && props.dataKey in selection) return String(selection[props.dataKey]) === key
46
+ return selection === row
47
+ }
48
+ const current = Array.isArray(selection) ? selection : []
49
+ if (props.dataKey) return current.some(s => s && typeof s === 'object' && props.dataKey in s && String(s[props.dataKey]) === key)
50
+ return current.includes(row)
51
+ }
52
+ const toggleRowSelection = (row, index) => {
53
+ if (!props.selectionMode) return
54
+ const selected = isRowSelected(row, index)
55
+ if (props.selectionMode === 'single') {
56
+ const next = selected ? null : row
57
+ internalSelection.value = next
58
+ emit('update:selection', next)
59
+ emit('updateSelection', next)
60
+ emit(selected ? 'rowUnselect' : 'rowSelect', { data: row })
61
+ return
62
+ }
63
+ const current = Array.isArray(effectiveSelection.value) ? effectiveSelection.value : []
64
+ const key = getRowKey(row, index)
65
+ const next = selected
66
+ ? (props.dataKey ? current.filter(r => String(r?.[props.dataKey]) !== key) : current.filter(r => r !== row))
67
+ : [...current, row]
68
+ internalSelection.value = next
69
+ emit('update:selection', next)
70
+ emit('updateSelection', next)
71
+ emit(selected ? 'rowUnselect' : 'rowSelect', { data: row })
72
+ }
73
+
74
+ const allVisibleSelected = computed(() => {
75
+ if (props.selectionMode !== 'multiple') return false
76
+ const rows = visibleRows.value
77
+ if (rows.length === 0) return false
78
+ for (let i = 0; i < rows.length; i++) {
79
+ if (!isRowSelected(rows[i], i + (internalFirst.value || 0))) return false
80
+ }
81
+ return true
82
+ })
83
+
84
+ const toggleAllVisible = () => {
85
+ if (props.selectionMode !== 'multiple') return
86
+ const current = Array.isArray(effectiveSelection.value) ? effectiveSelection.value : []
87
+ const rows = visibleRows.value
88
+ const startIndex = internalFirst.value || 0
89
+ if (rows.length === 0) return
90
+ if (allVisibleSelected.value) {
91
+ if (!props.dataKey) {
92
+ const next = current.filter(r => !rows.includes(r))
93
+ internalSelection.value = next
94
+ emit('update:selection', next)
95
+ emit('updateSelection', next)
96
+ return
97
+ }
98
+ const keys = rows.map((r, i) => getRowKey(r, startIndex + i))
99
+ const next = current.filter(r => !keys.includes(String(r?.[props.dataKey])))
100
+ internalSelection.value = next
101
+ emit('update:selection', next)
102
+ emit('updateSelection', next)
103
+ return
104
+ }
105
+ if (!props.dataKey) {
106
+ const next = [...current, ...rows.filter(r => !current.includes(r))]
107
+ internalSelection.value = next
108
+ emit('update:selection', next)
109
+ emit('updateSelection', next)
110
+ return
111
+ }
112
+ const existing = new Set(current.map(r => String(r?.[props.dataKey])))
113
+ const next = [...current, ...rows.filter((r) => !existing.has(String(r?.[props.dataKey])))]
114
+ internalSelection.value = next
115
+ emit('update:selection', next)
116
+ emit('updateSelection', next)
117
+ }
118
+ const getHeaderContent = (col) => (col.headerTemplate && typeof col.headerTemplate === 'function') ? col.headerTemplate(col) : col.header
119
+ const getRawValue = (row, col) => { if (!row) return ''; if (col.field && typeof row === 'object' && col.field in row) return row[col.field]; return '' }
120
+ const getCellContent = (row, col, index) => { const raw = getRawValue(row, col); if (col.body && typeof col.body === 'function') return col.body(row, { index, column: col, field: col.field, value: raw }); return raw }
121
+ const matchFilter = (value, query, mode) => { const q = String(query ?? '').toLowerCase().trim(); if (!q) return true; const v = String(value ?? '').toLowerCase(); if (mode === 'equals') return v === q; if (mode === 'startsWith') return v.startsWith(q); if (mode === 'endsWith') return v.endsWith(q); return v.includes(q) }
122
+ const filteredRows = computed(() => { const rows = props.value || []; if (props.lazy) return rows; const cols = normalizeColumns.value; const filters = effectiveFilters.value || {}; const global = String(filters.__global || '').trim(); const keys = Object.keys(filters).filter(k => k !== '__global'); if (!global && keys.length === 0) return rows; const globalFields = Array.isArray(props.globalFilterFields) && props.globalFilterFields.length ? props.globalFilterFields : cols.map(c => c.field); return rows.filter((row) => { if (global) { const ok = globalFields.some((f) => matchFilter(getRawValue(row, { field: f }), global, 'contains')); if (!ok) return false } for (const c of cols) { const f = filters[c.field]; if (!f) continue; if (!matchFilter(getRawValue(row, c), f.value, f.matchMode || c.filterMatchMode || 'contains')) return false } return true }) })
123
+ const sortedRows = computed(() => { if (props.lazy) return filteredRows.value; const rows = [...filteredRows.value]; const field = internalSortField.value; if (!field) return rows; const col = normalizeColumns.value.find(c => c.field === field); const order = internalSortOrder.value === -1 ? -1 : 1; const type = col?.type || 'text'; rows.sort((a, b) => { const av = getCellContent(a, { field }, -1); const bv = getCellContent(b, { field }, -1); if (type === 'number') return (Number(av) - Number(bv)) * order; return String(av ?? '').localeCompare(String(bv ?? ''), undefined, { numeric: true, sensitivity: 'base' }) * order }); return rows })
124
+ const totalRecords = computed(() => props.lazy ? (props.totalRecords || (props.value || []).length) : sortedRows.value.length)
125
+ const visibleRows = computed(() => props.lazy ? (props.value || []) : (!props.paginator ? sortedRows.value : sortedRows.value.slice(internalFirst.value || 0, (internalFirst.value || 0) + (internalRows.value || 10))))
126
+ const setSort = (col) => {
127
+ if (!col.sortable) return
128
+ const nextField = col.field
129
+ let nextOrder = 1
130
+ if (internalSortField.value === nextField) nextOrder = internalSortOrder.value === 1 ? -1 : 1
131
+ internalSortField.value = nextField
132
+ internalSortOrder.value = nextOrder
133
+ internalFirst.value = 0
134
+ emit('update:sortField', nextField)
135
+ emit('update:sortOrder', nextOrder)
136
+ emit('updateSortField', nextField)
137
+ emit('updateSortOrder', nextOrder)
138
+ emit('sort', { sortField: nextField, sortOrder: nextOrder })
139
+ }
140
+ const onSortClick = (e) => { const field = e.currentTarget?.dataset?.field; if (!field) return; const col = normalizeColumns.value.find(c => c.field === field); if (!col) return; setSort(col) }
141
+ const setGlobal = (e) => {
142
+ const next = e.target.value
143
+ const nextFilters = { ...(effectiveFilters.value || {}), __global: next }
144
+ if (props.filters && typeof props.filters === 'object') { emit('update:filters', nextFilters); emit('updateFilters', nextFilters) } else { internalFilters.value = nextFilters }
145
+ internalFirst.value = 0
146
+ emit('update:globalFilter', next)
147
+ emit('updateGlobalFilter', next)
148
+ emit('filter', { global: next, filters: nextFilters })
149
+ }
150
+ const setColumnFilter = (field, e) => { const next = e.target.value; const current = { ...(effectiveFilters.value || {}) }; const col = normalizeColumns.value.find(c => c.field === field); if (!next) delete current[field]; else current[field] = { value: next, matchMode: col?.filterMatchMode || current[field]?.matchMode || 'contains' }; if (props.filters && typeof props.filters === 'object') { emit('update:filters', current); emit('updateFilters', current) } else { internalFilters.value = current } internalFirst.value = 0; emit('filter', { field, value: next, filters: current }) }
151
+ const onColumnFilterInput = (e) => { const field = e.target?.dataset?.field; if (!field) return; setColumnFilter(field, e) }
152
+ const onPage = ({ first, rows }) => {
153
+ internalFirst.value = first
154
+ internalRows.value = rows
155
+ emit('update:first', first)
156
+ emit('update:rows', rows)
157
+ emit('updateFirst', first)
158
+ emit('updateRows', rows)
159
+ emit('page', { first, rows })
160
+ }
161
+ const getWidth = (col) => columnWidths.value[col.field] || col.width || ''
162
+ const startResize = (e) => { if (!props.resizableColumns) return; const field = e.currentTarget?.dataset?.field; if (!field) return; e.preventDefault(); e.stopPropagation(); const th = e.currentTarget?.parentElement; const base = th?.getBoundingClientRect?.().width || parseFloat(th?.style?.width || '') || 160; resizing.value = { field, startX: e.clientX, startW: base }; const onMove = (ev) => { if (!resizing.value) return; const delta = ev.clientX - resizing.value.startX; const next = Math.max(80, resizing.value.startW + delta); columnWidths.value = { ...columnWidths.value, [resizing.value.field]: `${Math.round(next)}px` } }; const onUp = () => { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); resizing.value = null }; document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp) }
163
+ </script>
164
+
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>
168
+ <div class="n-dt-wrapper">
169
+ <table class="n-dt-table" :class="{ 'is-striped': stripedRows, 'is-hover': hoverRows }">
170
+ <thead class="n-dt-thead">
171
+ <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>
173
+ <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
+ <div class="n-dt-th-content">
175
+ <span class="n-dt-th-text">{{ $slots.value && $slots.value[`header-${col.field}`] ? $slots[`header-${col.field}`]({ column: col }) : getHeaderContent(col) }}</span>
176
+ <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>
179
+ </span>
180
+ </div>
181
+ <span v-if="resizableColumns" class="n-dt-resizer" :data-field="col.field" @mousedown="startResize"></span>
182
+ </th>
183
+ </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>
185
+ </thead>
186
+ <tbody class="n-dt-tbody">
187
+ <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>
189
+ <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
+ {{ $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
+ </td>
192
+ </tr>
193
+ <tr v-if="visibleRows.value.length === 0" class="n-dt-empty-row"><td :colspan="normalizeColumns.value.length + (selectionMode ? 1 : 0)" class="n-dt-empty">{{ emptyMessage }}</td></tr>
194
+ </tbody>
195
+ </table>
196
+ </div>
197
+ <NPaginator v-if="paginator" :first="internalFirst.value" :rows="internalRows.value" :totalRecords="totalRecords.value" :rowsPerPageOptions="rowsPerPageOptions" @page="onPage" />
198
+ </div>
199
+ </template>
200
+
201
+ <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>
@@ -1,7 +1,7 @@
1
1
  import { signal, computed, inject, effect, batch, h, hText, defineComponent, registerComponent, reloadComponent, injectStyle } from 'nexa-framework'
2
2
 
3
3
  const _sfc_main = defineComponent({
4
- __scopeId: 'data-v-76a3e703',
4
+ __scopeId: 'data-v-39e23f1c',
5
5
  __hmrId: 'NInputNumber_nexa',
6
6
  props: {
7
7
  modelValue: { type: Number, default: 0 },
@@ -201,31 +201,31 @@ const _sfc_main = defineComponent({
201
201
  // Injected render function
202
202
  _sfc_main.render = function(ctx) {
203
203
  let { field, effectiveValue, effectiveDisabled, text, canEdit, isFocused, nfSignal, displayText, sanitize, clamp, parse, setValue, inc, dec, onInput, onBeforeInput, onPaste, onKeydown, onBlur, onFocus, inject, batch, $slots, emit, modelValue, min, max, step, bindField, disabled, readonly, label, placeholder, currency, locale, Fragment: _ntc_Fragment } = ctx
204
- return h('div', { class: "n-inum", "data-v-76a3e703": "" }, [
205
- "\n ",
206
- (label) ? h('label', { class: "n-inum-label", "data-v-76a3e703": "" }, [
204
+ return h('div', { class: "n-inum", "data-v-39e23f1c": "" }, [
205
+ "\r\n ",
206
+ (label) ? h('label', { class: "n-inum-label", "data-v-39e23f1c": "" }, [
207
207
  label
208
208
  ]) : null,
209
- h('div', { class: ["n-inum-wrap", { 'is-disabled': effectiveDisabled.value }], "data-v-76a3e703": "" }, [
210
- "\n ",
211
- h('button', { class: "n-inum-btn n-inum-dec", type: "button", disabled: effectiveDisabled.value || readonly, "aria-label": "Decrement", onClick: dec, "data-v-76a3e703": "" }, [
209
+ h('div', { class: ["n-inum-wrap", { 'is-disabled': effectiveDisabled.value }], "data-v-39e23f1c": "" }, [
210
+ "\r\n ",
211
+ h('button', { class: "n-inum-btn n-inum-dec", type: "button", disabled: effectiveDisabled.value || readonly, "aria-label": "Decrement", onClick: dec, "data-v-39e23f1c": "" }, [
212
212
  "−"
213
213
  ]),
214
- "\n ",
215
- h('input', { class: "n-inum-input", type: "text", value: displayText.value, placeholder: placeholder, disabled: effectiveDisabled.value, readonly: readonly, inputmode: "decimal", autocomplete: "off", onBeforeinput: onBeforeInput, onKeydown: onKeydown, onPaste: onPaste, onInput: onInput, onFocus: onFocus, onBlur: onBlur, "data-v-76a3e703": "" }),
216
- "\n ",
217
- h('button', { class: "n-inum-btn n-inum-inc", type: "button", disabled: effectiveDisabled.value || readonly, "aria-label": "Increment", onClick: inc, "data-v-76a3e703": "" }, [
214
+ "\r\n ",
215
+ h('input', { class: "n-inum-input", type: "text", value: displayText.value, placeholder: placeholder, disabled: effectiveDisabled.value, readonly: readonly, inputmode: "decimal", autocomplete: "off", onBeforeinput: onBeforeInput, onKeydown: onKeydown, onPaste: onPaste, onInput: onInput, onFocus: onFocus, onBlur: onBlur, "data-v-39e23f1c": "" }),
216
+ "\r\n ",
217
+ h('button', { class: "n-inum-btn n-inum-inc", type: "button", disabled: effectiveDisabled.value || readonly, "aria-label": "Increment", onClick: inc, "data-v-39e23f1c": "" }, [
218
218
  "+"
219
219
  ]),
220
- "\n "
220
+ "\r\n "
221
221
  ]),
222
- "\n "
222
+ "\r\n "
223
223
  ])
224
224
  }
225
- _sfc_main.__scopeId = 'data-v-76a3e703'
225
+ _sfc_main.__scopeId = 'data-v-39e23f1c'
226
226
  _sfc_main.__hmrId = 'NInputNumber_nexa'
227
227
 
228
228
  export default _sfc_main
229
229
 
230
- const __style = `.n-inum[data-v-76a3e703]{display:flex;flex-direction:column;gap:var(--n-space-2);width:100%;font-family:var(--n-font-sans)}.n-inum-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-inum-wrap{display:flex;align-items:stretch;min-height:44px;background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);overflow:hidden;transition:all var(--n-transition-fast)}.n-inum-wrap:focus-within{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-inum-input{flex:1;background:transparent;border:none;outline:none;padding:0.75rem 0.75rem;color:var(--n-color-text);font-size:var(--n-text-base);font-family:inherit;text-align:center;line-height:1.2;box-sizing:border-box}.n-inum-btn{width:2.5rem;background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:var(--n-text-base);transition:all var(--n-transition-fast)}.n-inum-btn:hover:not(:disabled){background:var(--n-color-glass);color:var(--n-color-text)}.n-inum-btn:disabled{opacity:0.5;cursor:not-allowed}.is-disabled{opacity:0.6;cursor:not-allowed;background:var(--n-color-surface-alt)}`
231
- injectStyle('data-v-76a3e703', __style)
230
+ const __style = `.n-inum[data-v-39e23f1c]{display:flex;flex-direction:column;gap:var(--n-space-2);width:100%;font-family:var(--n-font-sans)}.n-inum-label{display:block;font-size:var(--n-text-sm);font-weight:var(--n-weight-medium);color:var(--n-color-text-secondary);margin-bottom:var(--n-space-2)}.n-inum-wrap{display:flex;align-items:stretch;min-height:44px;background:var(--n-color-surface);border:1px solid var(--n-color-border);border-radius:var(--n-radius-md);overflow:hidden;transition:all var(--n-transition-fast)}.n-inum-wrap:focus-within{border-color:var(--n-color-primary);box-shadow:0 0 0 3px var(--n-color-primary-light)}.n-inum-input{flex:1;background:transparent;border:none;outline:none;padding:0.75rem 0.75rem;color:var(--n-color-text);font-size:var(--n-text-base);font-family:inherit;text-align:center;line-height:1.2;box-sizing:border-box}.n-inum-btn{width:2.5rem;background:transparent;border:none;color:var(--n-color-text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:var(--n-text-base);transition:all var(--n-transition-fast)}.n-inum-btn:hover:not(:disabled){background:var(--n-color-glass);color:var(--n-color-text)}.n-inum-btn:disabled{opacity:0.5;cursor:not-allowed}.is-disabled{opacity:0.6;cursor:not-allowed;background:var(--n-color-surface-alt)}`
231
+ injectStyle('data-v-39e23f1c', __style)