@dnax/ui 0.0.41 → 0.0.42
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/components/QSpreadsheet.vue +24 -16
- package/package.json +1 -1
|
@@ -400,12 +400,18 @@ const newRowKey = (): string => {
|
|
|
400
400
|
return `row-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
/**
|
|
403
|
+
/**
|
|
404
|
+
* Injecte `_key` (mutatif) uniquement sur les lignes qui n'en ont pas.
|
|
405
|
+
* Une clé DÉJÀ PRÉSENTE est toujours conservée, quelle que soit sa valeur
|
|
406
|
+
* (string, nombre, uuid ou non) : l'injection ne s'applique qu'à
|
|
407
|
+
* `undefined` / `null` / chaîne vide. Aucune réécriture, aucun dédoublonnage.
|
|
408
|
+
*/
|
|
404
409
|
const ensureRowKeys = (rows: Record<string, any>[] | undefined) => {
|
|
405
410
|
if (!Array.isArray(rows)) return
|
|
406
411
|
for (const row of rows) {
|
|
407
412
|
if (!row || typeof row !== "object") continue
|
|
408
|
-
|
|
413
|
+
const current = row[ROW_KEY]
|
|
414
|
+
if (current === undefined || current === null || current === "") row[ROW_KEY] = newRowKey()
|
|
409
415
|
}
|
|
410
416
|
}
|
|
411
417
|
|
|
@@ -687,22 +693,19 @@ const editingIsFormula = computed(() => {
|
|
|
687
693
|
if (!editing.value) return false
|
|
688
694
|
const col = colOf(editing.value.column)
|
|
689
695
|
if (!col || col.type === "boolean" || col.type === "select") return false
|
|
690
|
-
return draft.value.trim().startsWith("=")
|
|
696
|
+
return String(draft.value ?? "").trim().startsWith("=")
|
|
691
697
|
})
|
|
692
698
|
const editingIsSelect = computed(() => {
|
|
693
699
|
const col = editing.value ? colOf(editing.value.column) : undefined
|
|
694
700
|
return col?.type === "select"
|
|
695
701
|
})
|
|
696
702
|
const draftLines = computed(() =>
|
|
697
|
-
Math.min(5, Math.max(1, draft.value.split("\n").length)),
|
|
703
|
+
Math.min(5, Math.max(1, String(draft.value ?? "").split("\n").length)),
|
|
698
704
|
)
|
|
699
705
|
|
|
700
706
|
const editorInputType = computed(() => {
|
|
701
707
|
const col = editing.value ? colOf(editing.value.column) : undefined
|
|
702
708
|
switch (col?.type) {
|
|
703
|
-
case "number":
|
|
704
|
-
case "integer":
|
|
705
|
-
return "number"
|
|
706
709
|
case "email":
|
|
707
710
|
return "email"
|
|
708
711
|
case "url":
|
|
@@ -712,15 +715,20 @@ const editorInputType = computed(() => {
|
|
|
712
715
|
case "datetime":
|
|
713
716
|
return "datetime-local"
|
|
714
717
|
default:
|
|
718
|
+
// PAS de `type="number"` pour number/integer : (1) le navigateur refuse
|
|
719
|
+
// `=` (formule) ou un "-" isolé dans un input number, (2) `v-model` sur
|
|
720
|
+
// input[type=number] **caste la valeur en Number** → le brouillon n'était
|
|
721
|
+
// plus une string et tous les `.trim()` / `.split()` dessus explosaient.
|
|
722
|
+
// Le clavier numérique mobile est assuré par `inputmode` (`editorInputMode`).
|
|
715
723
|
return "text"
|
|
716
724
|
}
|
|
717
725
|
})
|
|
718
726
|
|
|
719
|
-
/**
|
|
720
|
-
const
|
|
727
|
+
/** Équivalent mobile de `type="number"` : clavier décimal / numérique sans cast */
|
|
728
|
+
const editorInputMode = computed(() => {
|
|
721
729
|
const col = editing.value ? colOf(editing.value.column) : undefined
|
|
722
|
-
if (col?.type === "number") return "
|
|
723
|
-
if (col?.type === "integer") return "
|
|
730
|
+
if (col?.type === "number") return "decimal"
|
|
731
|
+
if (col?.type === "integer") return "numeric"
|
|
724
732
|
return undefined
|
|
725
733
|
})
|
|
726
734
|
|
|
@@ -757,7 +765,7 @@ const positionEditor = () => {
|
|
|
757
765
|
// Une formule élargit l'éditeur (monospace ≈ 7.6px/car), sans dépasser le bord droit
|
|
758
766
|
const maxW = sc.width - (tr.left - sc.left) - 4
|
|
759
767
|
const ideal = editingIsFormula.value
|
|
760
|
-
? Math.min(480, Math.max(220, draft.value.length * 7.6 + 30))
|
|
768
|
+
? Math.min(480, Math.max(220, String(draft.value ?? "").length * 7.6 + 30))
|
|
761
769
|
: tr.width
|
|
762
770
|
const width = Math.min(maxW, Math.max(tr.width, ideal))
|
|
763
771
|
editorStyle.value = {
|
|
@@ -1499,7 +1507,7 @@ const selectOptions = computed<QSpreadsheetCellOption[]>(() => {
|
|
|
1499
1507
|
if (!editing.value) return []
|
|
1500
1508
|
const col = colOf(editing.value.column)
|
|
1501
1509
|
if (col?.type !== "select") return []
|
|
1502
|
-
const q = draft.value.trim().toLowerCase()
|
|
1510
|
+
const q = String(draft.value ?? "").trim().toLowerCase()
|
|
1503
1511
|
return (col.options ?? []).filter(
|
|
1504
1512
|
(o) => !q || String(o.label ?? o.value ?? "").toLowerCase().includes(q),
|
|
1505
1513
|
)
|
|
@@ -1689,8 +1697,8 @@ const acceptFx = () => {
|
|
|
1689
1697
|
const f = fxSuggestions.value[fxActive.value]
|
|
1690
1698
|
if (!f) return
|
|
1691
1699
|
const replaceTail = (s: string) => s.replace(/[A-Za-z]+$/, f.name + "(")
|
|
1692
|
-
if (editing.value) draft.value = replaceTail(draft.value)
|
|
1693
|
-
else fxDraft.value = replaceTail(fxDraft.value)
|
|
1700
|
+
if (editing.value) draft.value = replaceTail(String(draft.value ?? ""))
|
|
1701
|
+
else fxDraft.value = replaceTail(String(fxDraft.value ?? ""))
|
|
1694
1702
|
fxActive.value = 0
|
|
1695
1703
|
nextTick(() => {
|
|
1696
1704
|
const el = editing.value
|
|
@@ -4377,7 +4385,7 @@ defineExpose({
|
|
|
4377
4385
|
v-model="draft"
|
|
4378
4386
|
class="q-spreadsheet__editor-input"
|
|
4379
4387
|
:type="editorInputType"
|
|
4380
|
-
:
|
|
4388
|
+
:inputmode="editorInputMode"
|
|
4381
4389
|
:placeholder="editingCol.type === 'select' ? 'Type to filter…' : ''"
|
|
4382
4390
|
@keydown="onEditKeydown"
|
|
4383
4391
|
@blur="commitEdit"
|