@dnax/ui 0.0.20 → 0.0.22

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.
@@ -162,8 +162,11 @@ const sheetTitle = computed(
162
162
 
163
163
  // — Swipe down pour fermer (mode sheet, opt-in swipe-to-close) —
164
164
  const dragging = ref(false)
165
+ const swipeClosing = ref(false)
165
166
  let dragStartY = 0
166
167
  let dragDy = 0
168
+ let swipeCloseTimer: number | undefined
169
+
167
170
  const canSwipe = computed(() => props.swipeToClose && props.mode === "sheet")
168
171
 
169
172
  const onDragStart = (e: PointerEvent) => {
@@ -183,16 +186,39 @@ const onDragMove = (e: PointerEvent) => {
183
186
  const onDragEnd = () => {
184
187
  if (!dragging.value) return
185
188
  dragging.value = false
186
- if (dragDy > 80) closePopup()
187
- else if (sheetRef.value) sheetRef.value.style.transform = ""
189
+ if (dragDy > 80) {
190
+ // Au-delà du seuil : on CONTINUE le glissement jusqu'à sortie complète
191
+ // (translateY(100%)) puis on ferme à la fin de la transition — au lieu de
192
+ // laisser le panneau revenir en place avant le fade (saut visuel).
193
+ swipeClosing.value = true
194
+ if (sheetRef.value) sheetRef.value.style.transform = "translateY(100%)"
195
+ window.clearTimeout(swipeCloseTimer)
196
+ swipeCloseTimer = window.setTimeout(() => {
197
+ swipeClosing.value = false
198
+ closePopup()
199
+ }, 400) // fallback si la transition ne se déclenche pas (déjà à 100%, reduced-motion)
200
+ }
201
+ else if (sheetRef.value) {
202
+ // Sous le seuil : retour en douceur à la position initiale
203
+ sheetRef.value.style.transform = ""
204
+ }
188
205
  dragDy = 0
189
206
  }
190
207
 
208
+ // Ferme dès que la transition de glissement se termine (plus précis que le timeout)
209
+ const onSheetTransitionEnd = (e: TransitionEvent) => {
210
+ if (e.propertyName !== "transform" || !swipeClosing.value) return
211
+ window.clearTimeout(swipeCloseTimer)
212
+ swipeClosing.value = false
213
+ closePopup()
214
+ }
215
+
191
216
  const sheetClasses = computed(() => [
192
217
  `q-autocomplete__sheet--${props.mode}`,
193
218
  modeOptions.value?.class,
194
219
  dragging.value && "q-autocomplete__sheet--dragging",
195
220
  canSwipe.value && "q-autocomplete__sheet--swipeable",
221
+ swipeClosing.value && "q-autocomplete__sheet--swipe-closing",
196
222
  ])
197
223
 
198
224
  // — Valeurs des options —
@@ -280,6 +306,15 @@ const onClear = () => {
280
306
  emit("clear")
281
307
  }
282
308
 
309
+ // Clear du champ de recherche du panneau (sheet/modal) : vide la recherche
310
+ // sans effacer la sélection, garde le focus dans l'input
311
+ const onSearchClear = () => {
312
+ query.value = ""
313
+ emit("update:inputValue", "")
314
+ activeIndex.value = 0
315
+ nextTick(() => panelInput.value?.focus())
316
+ }
317
+
283
318
  const isSelected = (opt: any) => getValue(opt) === props.modelValue
284
319
 
285
320
  // À la perte de focus : si le texte saisi ne correspond exactement à aucune
@@ -362,6 +397,7 @@ onMounted(() => {
362
397
  })
363
398
  onBeforeUnmount(() => {
364
399
  if (typeof document !== "undefined") document.removeEventListener("mousedown", onDocMousedown)
400
+ window.clearTimeout(swipeCloseTimer)
365
401
  })
366
402
 
367
403
  // Verrou du scroll de la page derrière le panneau (modal/sheet)
@@ -471,6 +507,7 @@ watch(open, (v) => {
471
507
  role="dialog"
472
508
  aria-modal="true"
473
509
  :aria-label="sheetTitle"
510
+ @transitionend="onSheetTransitionEnd"
474
511
  >
475
512
  <div
476
513
  class="q-autocomplete__sheet-header"
@@ -502,6 +539,15 @@ watch(open, (v) => {
502
539
  @input="onInput"
503
540
  @keydown="onKeydown"
504
541
  />
542
+ <button
543
+ v-if="query !== ''"
544
+ type="button"
545
+ class="q-autocomplete__search-clear"
546
+ aria-label="Effacer la recherche"
547
+ @mousedown.prevent="onSearchClear"
548
+ >
549
+ <Icon :icon="icons.x" aria-hidden="true" />
550
+ </button>
505
551
  </div>
506
552
  <div
507
553
  ref="popupRef"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dnax/ui",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "module": "index.ts",
5
5
  "description": "UI design System",
6
6
  "type": "module",
package/styles/main.css CHANGED
@@ -3474,6 +3474,12 @@ html.dark body {
3474
3474
  transition: none;
3475
3475
  }
3476
3476
 
3477
+ /* fermeture par swipe : le glissement (translateY 100%) gère la sortie —
3478
+ l'animation leave (pop-out 24px) serait un saut depuis la position glissée */
3479
+ .q-autocomplete-modal-leave-active .q-autocomplete__sheet--swipe-closing {
3480
+ animation: none;
3481
+ }
3482
+
3477
3483
  /* le header est la zone qui attrape le swipe (cursor grab) — seulement si
3478
3484
  swipe-to-close est actif (classe --swipeable) */
3479
3485
  .q-autocomplete__sheet--swipeable .q-autocomplete__sheet-header {
@@ -3571,6 +3577,27 @@ html.dark body {
3571
3577
  .q-autocomplete__search-input::placeholder {
3572
3578
  color: rgb(0 0 0 / 0.45);
3573
3579
  }
3580
+ .q-autocomplete__search-clear {
3581
+ display: inline-flex;
3582
+ align-items: center;
3583
+ justify-content: center;
3584
+ width: 20px;
3585
+ height: 20px;
3586
+ padding: 0;
3587
+ border: none;
3588
+ border-radius: 50%;
3589
+ background: rgb(0 0 0 / 0.15);
3590
+ color: inherit;
3591
+ cursor: pointer;
3592
+ flex-shrink: 0;
3593
+ }
3594
+ .q-autocomplete__search-clear:hover {
3595
+ background: rgb(0 0 0 / 0.25);
3596
+ }
3597
+ .q-autocomplete__search-clear svg {
3598
+ width: 12px;
3599
+ height: 12px;
3600
+ }
3574
3601
  .q-autocomplete__sheet-list {
3575
3602
  overflow-y: auto;
3576
3603
  padding: 6px;