@dnax/ui 0.0.73 → 0.0.76

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.
@@ -31,6 +31,7 @@ export interface DropdownItem {
31
31
  import { computed } from "vue"
32
32
  import type { StyleValue } from "vue"
33
33
  import QBtnActions, { type DropdownPosition } from "./QBtnActions.vue"
34
+ import { useRadius } from "../lib/useComponentProps"
34
35
  import type { RadiusProp } from "../lib/useComponentProps"
35
36
 
36
37
  interface Props {
@@ -115,6 +116,12 @@ const mappedActions = computed(() =>
115
116
  )
116
117
 
117
118
  const onSelectAction = (value: any) => emit("select", value)
119
+
120
+ // radius : prop explicite > composantProps.QBtnDropdown > composantProps.default.
121
+ // On transmet la valeur **résolue** (et non la prop brute) pour que
122
+ // `componentProps.QBtnDropdown.radius` ne soit pas ignoré au profit de celui du
123
+ // moteur QBtnActions.
124
+ const effectiveRadius = useRadius("QBtnDropdown", () => props.radius)
118
125
  </script>
119
126
 
120
127
  <template>
@@ -134,7 +141,7 @@ const onSelectAction = (value: any) => emit("select", value)
134
141
  :color="color"
135
142
  :text-color="textColor"
136
143
  :size="size"
137
- :radius="radius"
144
+ :radius="effectiveRadius"
138
145
  :flat="flat"
139
146
  :outline="outline"
140
147
  :unelevated="unelevated"
@@ -3,7 +3,7 @@
3
3
  // Pas d'ombre par défaut ; elevated l'ajoute, flat la retire explicitement.
4
4
  // Slots : default, media (zone image en haut), actions (zone actions en bas)
5
5
  import { computed } from "vue"
6
- import { radiusStyle, useRadius } from "../lib/useComponentProps"
6
+ import { radiusStyleNative, useRadius } from "../lib/useComponentProps"
7
7
  import type { RadiusProp } from "../lib/useComponentProps"
8
8
 
9
9
  interface Props {
@@ -35,9 +35,9 @@ const props = withDefaults(defineProps<Props>(), {
35
35
  hover: false,
36
36
  })
37
37
 
38
- // radius : prop explicite > composantProps.QCard.radius ; échelle → --q-radius
38
+ // radius : prop explicite > composantProps.QCard.radius ; échelle → --q-radius (true = md)
39
39
  const effectiveRadius = useRadius("QCard", () => props.radius)
40
- const roundedStyle = computed(() => radiusStyle(effectiveRadius.value))
40
+ const roundedStyle = computed(() => radiusStyleNative(effectiveRadius.value))
41
41
  </script>
42
42
 
43
43
  <template>
@@ -14,7 +14,7 @@ export const qDialogKey: InjectionKey<DialogContext> = Symbol("q-dialog")
14
14
  import { computed, onBeforeUnmount, onMounted, provide, watch } from "vue"
15
15
  import type { StyleValue } from "vue"
16
16
  import { cn } from "../lib/utils"
17
- import { radiusStyle, useRadius } from "../lib/useComponentProps"
17
+ import { radiusStyleNative, useRadius } from "../lib/useComponentProps"
18
18
  import type { RadiusProp } from "../lib/useComponentProps"
19
19
  import { useOverlayBack } from "../lib/overlayBack"
20
20
  import { markOverlayClose } from "../lib/closeOverlay"
@@ -150,7 +150,7 @@ const overlayClasses = computed(() => cn("q-dialog__overlay", `q-dialog__overlay
150
150
 
151
151
  // radius : prop explicite > composantProps.QDialog.radius ; échelle → --q-radius
152
152
  const effectiveRadius = useRadius("QDialog", () => props.radius)
153
- const roundedStyle = computed(() => radiusStyle(effectiveRadius.value))
153
+ const roundedStyle = computed(() => radiusStyleNative(effectiveRadius.value))
154
154
 
155
155
  const contentClasses = computed(() =>
156
156
  cn(
@@ -6,6 +6,8 @@ import { computed, onBeforeUnmount, reactive, ref, watch } from "vue"
6
6
  import { Icon } from "@iconify/vue"
7
7
  import { icons } from "../lib/icons"
8
8
  import { cn } from "../lib/utils"
9
+ import { fileIconKind, formatFileSize, selectFiles } from "../lib/fileList"
10
+ import type { FileIconKind } from "../lib/fileList"
9
11
 
10
12
  interface Props {
11
13
  /** Fichier(s) sélectionné(s) — File (simple) ou File[] (multiple) */
@@ -100,51 +102,20 @@ const fileKey = (file: File): number => {
100
102
  return id
101
103
  }
102
104
 
103
- // — Icône par type de fichier (fallback générique) —
104
- const ARCHIVE_EXT = /\.(zip|rar|7z|tar|gz|bz2|xz|tgz)$/
105
- const SPREADSHEET_EXT = /\.(xlsx|xls|csv|ods|tsv)$/
106
- const CODE_EXT = /\.(json|js|mjs|cjs|ts|jsx|tsx|html?|xml|css|scss|sass|less|vue|py|java|c|cpp|h|hpp|sh|bash|yml|yaml|toml|ini|go|rs|php|rb|swift|kt)$/
107
-
108
- const iconFor = (file: File): string => {
109
- const type = file.type
110
- const name = file.name.toLowerCase()
111
- if (type.startsWith("video/")) return icons.fileVideo
112
- if (type.startsWith("audio/")) return icons.fileAudio
113
- if (ARCHIVE_EXT.test(name) || /zip|compressed/.test(type)) return icons.fileArchive
114
- if (SPREADSHEET_EXT.test(name) || type.includes("spreadsheet") || type.includes("excel")) {
115
- return icons.fileSpreadsheet
116
- }
117
- if (CODE_EXT.test(name)) return icons.fileCode
118
- if (type.startsWith("image/")) return icons.fileImage
119
- return icons.fileText
105
+ // — Icône par type de fichier (règles partagées avec QSpreadsheet `attachment`) —
106
+ const ICON_BY_KIND: Record<FileIconKind, string> = {
107
+ image: icons.fileImage,
108
+ video: icons.fileVideo,
109
+ audio: icons.fileAudio,
110
+ archive: icons.fileArchive,
111
+ spreadsheet: icons.fileSpreadsheet,
112
+ code: icons.fileCode,
113
+ file: icons.fileText,
120
114
  }
121
115
 
122
- const formatSize = (bytes: number): string => {
123
- if (bytes >= 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} Go`
124
- if (bytes >= 1024 * 1024) return `${Math.round(bytes / (1024 * 1024))} Mo`
125
- if (bytes >= 1024) return `${Math.round(bytes / 1024)} Ko`
126
- return `${bytes} o`
127
- }
116
+ const iconFor = (file: File): string => ICON_BY_KIND[fileIconKind(file)]
128
117
 
129
- // — Validation —
130
- const acceptsFile = (file: File): boolean => {
131
- const accept = props.accept.trim()
132
- if (!accept) return true
133
- const patterns = accept
134
- .split(",")
135
- .map((p) => p.trim().toLowerCase())
136
- .filter(Boolean)
137
- if (patterns.length === 0) return true
138
- const name = file.name.toLowerCase()
139
- return patterns.some((p) => {
140
- if (p === "image/*") return file.type.startsWith("image/")
141
- if (p === "video/*") return file.type.startsWith("video/")
142
- if (p === "audio/*") return file.type.startsWith("audio/")
143
- if (p.startsWith(".")) return name.endsWith(p)
144
- if (p.includes("/")) return file.type.toLowerCase() === p
145
- return false
146
- })
147
- }
118
+ const formatSize = formatFileSize
148
119
 
149
120
  const formatMaxSize = () => {
150
121
  const bytes = props.maxFileSize
@@ -176,26 +147,12 @@ const onInputChange = (e: Event) => {
176
147
 
177
148
  const addFiles = (incoming: File[]) => {
178
149
  const current = files.value
179
- const valid: File[] = []
180
- const rejections: { file: File; reason: "size" | "type" | "count" }[] = []
181
-
182
- for (const file of incoming) {
183
- if (props.maxFileSize > 0 && file.size > props.maxFileSize) {
184
- rejections.push({ file, reason: "size" })
185
- continue
186
- }
187
- if (!acceptsFile(file)) {
188
- rejections.push({ file, reason: "type" })
189
- continue
190
- }
191
- valid.push(file)
192
- }
193
-
194
- const quota = props.maxFiles > 0 ? props.maxFiles : Infinity
195
- const remaining = quota === Infinity ? Infinity : Math.max(0, quota - current.length)
196
- const accepted = remaining === Infinity ? valid : valid.slice(0, remaining)
197
- const overflow = remaining === Infinity ? [] : valid.slice(remaining)
198
- for (const file of overflow) rejections.push({ file, reason: "count" })
150
+ const { accepted, rejected } = selectFiles(incoming, {
151
+ accept: props.accept,
152
+ maxSize: props.maxFileSize,
153
+ maxFiles: props.maxFiles,
154
+ current: current.length,
155
+ })
199
156
 
200
157
  if (accepted.length > 0) {
201
158
  const next = props.multiple ? [...current, ...accepted] : accepted[0]!
@@ -203,14 +160,14 @@ const addFiles = (incoming: File[]) => {
203
160
  for (const file of accepted) emit("add", file)
204
161
  }
205
162
 
206
- if (rejections.length > 0) {
207
- const reasons = [...new Set(rejections.map((r) => r.reason))]
163
+ if (rejected.length > 0) {
164
+ const reasons = [...new Set(rejected.map((r) => r.reason))]
208
165
  const parts: string[] = []
209
166
  if (reasons.includes("size")) parts.push(`Fichier trop lourd (max ${formatMaxSize()})`)
210
167
  if (reasons.includes("type")) parts.push("Type de fichier non accepté")
211
168
  if (reasons.includes("count")) parts.push(`Nombre maximum : ${props.maxFiles}`)
212
169
  internalError.value = parts.join(" · ")
213
- for (const r of rejections) emit("rejected", r.file, r.reason)
170
+ for (const r of rejected) emit("rejected", r.file, r.reason)
214
171
  }
215
172
  }
216
173
 
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- // QGridItem — cellule de la grille style Vant : <q-grid-item icon="lucide:photo" text="Photos" badge="3" />
2
+ // QGridItem — cellule de la grille style Vant : <q-grid-item icon="lucide:image" text="Photos" badge="3" />
3
3
  // À utiliser dans <q-grid :column-num="…">. Affiche une icône (ou un slot) + un
4
4
  // texte, avec badge / point de notification, effet cliquable et navigation (href).
5
5
  import { computed } from "vue"
@@ -77,8 +77,10 @@ const imageClasses = computed(() =>
77
77
  )
78
78
 
79
79
  // radius : prop explicite > composantProps.QImg > composantProps.default → --q-radius
80
+ // `true` = pilule (forme native documentée) → classe dédiée, pas un `--q-radius`
80
81
  const effectiveRadius = useRadius("QImg", () => props.radius)
81
82
  const roundedStyle = computed(() => radiusStyle(effectiveRadius.value))
83
+ const roundedClass = computed(() => (effectiveRadius.value === true ? "q-img--rounded" : undefined))
82
84
 
83
85
  const imageStyle = computed(() => `${props.imgStyle}; object-position: ${props.position}`)
84
86
 
@@ -101,7 +103,7 @@ const showLoading = computed(() => props.loading || imgLoading.value)
101
103
  </script>
102
104
 
103
105
  <template>
104
- <div class="q-img" :style="[containerStyle, roundedStyle]">
106
+ <div class="q-img" :class="roundedClass" :style="[containerStyle, roundedStyle]">
105
107
  <!-- Placeholder basse résolution pendant le chargement -->
106
108
  <img
107
109
  v-if="placeholderSrc && imgLoading && !imgError"
@@ -190,6 +190,8 @@ const rootClasses = computed(() =>
190
190
  props.dense && "q-field--dense",
191
191
  props.error && "q-field--error",
192
192
  props.disable && "q-field--disabled",
193
+ // `radius: true` = pilule (forme native documentée)
194
+ effectiveRadius.value === true && "q-input-otp--rounded",
193
195
  ),
194
196
  )
195
197