@dnax/ui 0.0.10 → 0.0.12

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/styles/main.css CHANGED
@@ -66,9 +66,14 @@ body {
66
66
  /* Safe-area intégrées à la règle de base .q-footer (plus bas) */
67
67
 
68
68
  /* Contenu de page : pas de padding par défaut (barres dans le flux).
69
- Compensation UNIQUEMENT si une barre est fixée (:has) : 50px + safe-area */
69
+ Compensation UNIQUEMENT si une barre est fixée (:has) : 50px + safe-area.
70
+ Safe-area bas : le contenu scroillé jusqu'au bout ne passe pas sous la barre
71
+ d'accueil iOS. */
70
72
  .q-page {
71
73
  flex: 1 1 auto; /* prend l'espace restant */
74
+ padding-bottom: 0;
75
+ padding-bottom: constant(safe-area-inset-bottom);
76
+ padding-bottom: env(safe-area-inset-bottom);
72
77
  }
73
78
 
74
79
  .q-app:has(.q-header--fixed) .q-page {
@@ -708,11 +713,30 @@ html.dark body {
708
713
  height: 2px;
709
714
  background-color: var(--q-tabs-active-color);
710
715
  transition:
711
- transform 0.25s ease,
712
- width 0.25s ease;
716
+ transform var(--q-tabs-duration, 0.25s) ease,
717
+ width var(--q-tabs-duration, 0.25s) ease;
713
718
  will-change: transform, width;
714
719
  }
715
720
 
721
+ /* — transitions animées (prop animated + transition) —
722
+ L'indicateur est la star du changement de tab : chaque preset lui donne une
723
+ courbe différente (spring = léger overshoot, smooth = expo-out velouté,
724
+ elastic = rebond marqué). */
725
+ .q-tabs--animated .q-tabs__indicator {
726
+ transition-duration: var(--q-tabs-duration, 0.45s);
727
+ }
728
+ .q-tabs--anim-spring .q-tabs__indicator {
729
+ transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); /* back-out : dépasse puis se pose */
730
+ }
731
+ .q-tabs--anim-smooth .q-tabs__indicator {
732
+ transition-duration: var(--q-tabs-duration, 0.5s);
733
+ transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1); /* expo-out : glisse velouté */
734
+ }
735
+ .q-tabs--anim-elastic .q-tabs__indicator {
736
+ transition-duration: var(--q-tabs-duration, 0.6s);
737
+ transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55); /* rebond prononcé */
738
+ }
739
+
716
740
  /* ===== QTabPanels / QTabPanel ===== */
717
741
  .q-tab-panels {
718
742
  position: relative;
@@ -801,7 +825,9 @@ html.dark body {
801
825
  padding: 0 16px;
802
826
  border: none;
803
827
  background: transparent;
804
- color: inherit;
828
+ /* Couleur des tabs inactifs : inactive-color (QTabs) sinon couleur héritée.
829
+ .q-tab--active (plus bas) reprend la main par ordre de source. */
830
+ color: var(--q-tabs-inactive-color, inherit);
805
831
  font: inherit;
806
832
  font-size: 14px;
807
833
  font-weight: 500;
@@ -822,9 +848,15 @@ html.dark body {
822
848
  transform: scale(0.94);
823
849
  }
824
850
 
825
- /* pop du tab actif (overshoot, prop animated) */
826
- .q-tabs--animated .q-tab--active {
827
- animation: q-tab-pop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
851
+ /* pop du tab actif (overshoot) spring (défaut) et elastic */
852
+ .q-tabs--anim-spring .q-tab--active,
853
+ .q-tabs--anim-elastic .q-tab--active {
854
+ animation: q-tab-pop var(--q-tabs-duration, 0.3s) cubic-bezier(0.34, 1.56, 0.64, 1);
855
+ }
856
+
857
+ /* smooth : le contenu du tab actif monte et apparaît (label + icône) */
858
+ .q-tabs--anim-smooth .q-tab--active .q-tab__content {
859
+ animation: q-tab-rise var(--q-tabs-duration, 0.32s) cubic-bezier(0.16, 1, 0.3, 1) both;
828
860
  }
829
861
 
830
862
  .q-tab--active {
@@ -837,8 +869,12 @@ html.dark body {
837
869
  outline-offset: -2px;
838
870
  }
839
871
 
840
- .q-tab:hover {
841
- background-color: rgb(0 0 0 / 0.04);
872
+ /* Mobile : le :hover reste collé après le tap (pas de souris) → réservé aux
873
+ devices avec hover réel (souris / trackpad) */
874
+ @media (hover: hover) and (pointer: fine) {
875
+ .q-tab:hover {
876
+ background-color: rgb(0 0 0 / 0.04);
877
+ }
842
878
  }
843
879
 
844
880
  .q-tab:disabled,
@@ -928,6 +964,63 @@ html.dark body {
928
964
  }
929
965
  }
930
966
 
967
+ @keyframes q-tab-rise {
968
+ from {
969
+ opacity: 0;
970
+ transform: translateY(6px);
971
+ }
972
+ to {
973
+ opacity: 1;
974
+ transform: none;
975
+ }
976
+ }
977
+
978
+ /* — collapse-inactive : les tabs inactifs ne montrent que l'icône ; le tab
979
+ actif s'étend (icône + label) avec une largeur animée (pattern mobile
980
+ bottom-nav). max-width 0 → 999px : la largeur utilisée = min(naturelle, max)
981
+ → le label se déplie jusqu'à sa largeur réelle, le tab suit.
982
+ PAS d'overflow: hidden : le texte n'est pas tronqué pendant l'ouverture —
983
+ il apparaît entier en FONDU (opacity), plus joli que le glissement. */
984
+ .q-tabs--collapse-inactive .q-tab__content {
985
+ gap: 0;
986
+ }
987
+ .q-tabs--collapse-inactive .q-tab__label {
988
+ max-width: 0;
989
+ opacity: 0;
990
+ white-space: nowrap; /* pas de retour à la ligne pendant l'ouverture */
991
+ transition:
992
+ max-width var(--q-tabs-duration, 0.3s) cubic-bezier(0.16, 1, 0.3, 1),
993
+ opacity var(--q-tabs-duration, 0.25s) ease;
994
+ }
995
+ .q-tabs--collapse-inactive .q-tab--active .q-tab__content {
996
+ gap: 6px;
997
+ }
998
+ .q-tabs--collapse-inactive .q-tab--active .q-tab__label {
999
+ max-width: 999px;
1000
+ opacity: 1;
1001
+ }
1002
+
1003
+ /* Crossfade : pendant que le label du tab inactif s'estompe, celui du tab
1004
+ actif apparaît en fondu — simultanément. Les animations d'entrée du tab
1005
+ (pop/rise) sont neutralisées en mode collapse pour ne pas geler ou masquer
1006
+ le fade du label entrant ; l'indicateur garde son spring (transition width). */
1007
+ .q-tabs--collapse-inactive.q-tabs--anim-spring .q-tab--active,
1008
+ .q-tabs--collapse-inactive.q-tabs--anim-elastic .q-tab--active,
1009
+ .q-tabs--collapse-inactive.q-tabs--anim-smooth .q-tab--active .q-tab__content {
1010
+ animation: none;
1011
+ }
1012
+
1013
+ @media (prefers-reduced-motion: reduce) {
1014
+ .q-tabs--animated .q-tabs__indicator,
1015
+ .q-tabs--anim-spring .q-tab--active,
1016
+ .q-tabs--anim-elastic .q-tab--active,
1017
+ .q-tabs--anim-smooth .q-tab--active .q-tab__content,
1018
+ .q-tabs--collapse-inactive .q-tab__label {
1019
+ transition-duration: 0s;
1020
+ animation: none;
1021
+ }
1022
+ }
1023
+
931
1024
  .q-tab__content {
932
1025
  display: flex;
933
1026
  flex-direction: inherit;
@@ -4492,11 +4585,8 @@ html.dark body {
4492
4585
  }
4493
4586
 
4494
4587
  .q-bottom-sheet__header {
4495
- display: flex;
4496
- align-items: flex-start;
4497
- justify-content: space-between;
4498
- gap: 12px;
4499
- padding: 12px 16px 8px;
4588
+ padding: 0; /* le padding est porté par le <q-toolbar> embarqué */
4589
+ border-bottom: 1px solid rgb(0 0 0 / 0.08);
4500
4590
  }
4501
4591
 
4502
4592
  .q-bottom-sheet__header-text {
@@ -4546,11 +4636,17 @@ html.dark body {
4546
4636
  }
4547
4637
 
4548
4638
  .q-bottom-sheet__footer {
4549
- display: flex;
4550
- align-items: center;
4551
- justify-content: flex-end;
4552
- gap: 8px;
4553
- padding: 8px 16px 16px;
4639
+ padding: 0; /* le padding est porté par le <q-toolbar> embarqué */
4640
+ border-top: 1px solid rgb(0 0 0 / 0.08);
4641
+ }
4642
+
4643
+ .q-bottom-sheet__footer .q-toolbar {
4644
+ justify-content: flex-end; /* actions alignées à droite (défaut) */
4645
+ }
4646
+
4647
+ .q-bottom-sheet__panel--dark .q-bottom-sheet__header,
4648
+ .q-bottom-sheet__panel--dark .q-bottom-sheet__footer {
4649
+ border-color: rgb(255 255 255 / 0.12);
4554
4650
  }
4555
4651
 
4556
4652
  /* — transitions (slide vertical type vaul) — */
@@ -5815,14 +5911,28 @@ html.dark body {
5815
5911
 
5816
5912
  /* safe-area : l'encoche en haut est gérée par le header, la barre d'accueil en bas par le footer */
5817
5913
  .q-dialog__content--maximized .q-dialog__header,
5818
- .q-dialog__content--top .q-dialog__header {
5914
+ .q-dialog__content--top .q-dialog__header,
5915
+ .q-dialog__content--left .q-dialog__header,
5916
+ .q-dialog__content--right .q-dialog__header {
5819
5917
  padding-top: 0;
5820
5918
  padding-top: constant(safe-area-inset-top);
5821
5919
  padding-top: env(safe-area-inset-top);
5822
5920
  }
5823
5921
 
5922
+ /* fullscreen en paysage : l'encoche latérale passe dans le header (comme QHeader) */
5923
+ .q-dialog__content--maximized .q-dialog__header {
5924
+ padding-left: 0;
5925
+ padding-left: constant(safe-area-inset-left);
5926
+ padding-left: env(safe-area-inset-left);
5927
+ padding-right: 0;
5928
+ padding-right: constant(safe-area-inset-right);
5929
+ padding-right: env(safe-area-inset-right);
5930
+ }
5931
+
5824
5932
  .q-dialog__content--maximized .q-dialog__footer,
5825
- .q-dialog__content--bottom .q-dialog__footer {
5933
+ .q-dialog__content--bottom .q-dialog__footer,
5934
+ .q-dialog__content--left .q-dialog__footer,
5935
+ .q-dialog__content--right .q-dialog__footer {
5826
5936
  padding-bottom: 0;
5827
5937
  padding-bottom: constant(safe-area-inset-bottom);
5828
5938
  padding-bottom: env(safe-area-inset-bottom);
@@ -5844,11 +5954,7 @@ html.dark body {
5844
5954
  position: sticky;
5845
5955
  top: 0;
5846
5956
  z-index: 1;
5847
- display: flex;
5848
- align-items: flex-start;
5849
- justify-content: space-between;
5850
- gap: 12px;
5851
- padding: 16px;
5957
+ padding: 0; /* le padding est porté par le <q-toolbar> embarqué */
5852
5958
  border-bottom: 1px solid rgb(0 0 0 / 0.08);
5853
5959
  background-color: inherit; /* reste opaque pendant le scroll du body */
5854
5960
  }
@@ -5899,15 +6005,26 @@ html.dark body {
5899
6005
  position: sticky;
5900
6006
  bottom: 0;
5901
6007
  z-index: 1;
5902
- display: flex;
5903
- align-items: center;
5904
- justify-content: flex-end;
5905
- gap: 8px;
5906
- padding: 12px 16px 16px;
6008
+ padding: 0; /* le padding est porté par le <q-toolbar> embarqué */
5907
6009
  border-top: 1px solid rgb(0 0 0 / 0.08);
5908
6010
  background-color: inherit;
5909
6011
  }
5910
6012
 
6013
+ .q-dialog__footer .q-toolbar {
6014
+ justify-content: flex-end; /* actions alignées à droite (défaut) */
6015
+ }
6016
+
6017
+ .q-dialog__body {
6018
+ min-height: 0;
6019
+ padding: 4px 16px 16px;
6020
+ }
6021
+
6022
+ .q-dialog__body--scrollable {
6023
+ flex: 1 1 auto;
6024
+ overflow-y: auto;
6025
+ overscroll-behavior: contain;
6026
+ }
6027
+
5911
6028
  .q-dialog__trigger {
5912
6029
  display: inline-flex;
5913
6030
  align-items: center;
@@ -6237,6 +6354,58 @@ html.dark body {
6237
6354
  }
6238
6355
  }
6239
6356
 
6357
+ /* swipe-* : le panneau glisse depuis un bord et y REVIENT à la fermeture
6358
+ (aller-retour, comme la sidebar) — swipe-left : vient de la droite et y
6359
+ retourne ; swipe-right : vient de la gauche et y retourne. */
6360
+ .q-dialog-swipe-left-enter-active,
6361
+ .q-dialog-swipe-left-leave-active,
6362
+ .q-dialog-swipe-right-enter-active,
6363
+ .q-dialog-swipe-right-leave-active {
6364
+ transition: opacity var(--q-dialog-duration-enter, 0.2s) ease;
6365
+ }
6366
+
6367
+ .q-dialog-swipe-left-enter-active .q-dialog__content,
6368
+ .q-dialog-swipe-left-leave-active .q-dialog__content {
6369
+ --q-dialog-swipe-x: 100vw;
6370
+ }
6371
+
6372
+ .q-dialog-swipe-right-enter-active .q-dialog__content,
6373
+ .q-dialog-swipe-right-leave-active .q-dialog__content {
6374
+ --q-dialog-swipe-x: -100vw;
6375
+ }
6376
+
6377
+ .q-dialog-swipe-left-enter-active .q-dialog__content,
6378
+ .q-dialog-swipe-right-enter-active .q-dialog__content {
6379
+ animation: q-dialog-swipe-in var(--q-dialog-duration-enter, 0.3s) cubic-bezier(0.32, 0.72, 0, 1);
6380
+ }
6381
+
6382
+ .q-dialog-swipe-left-leave-active .q-dialog__content,
6383
+ .q-dialog-swipe-right-leave-active .q-dialog__content {
6384
+ animation: q-dialog-swipe-out var(--q-dialog-duration-leave, 0.2s) ease-in forwards;
6385
+ }
6386
+
6387
+ @keyframes q-dialog-swipe-in {
6388
+ from {
6389
+ opacity: 0.6;
6390
+ transform: translateX(var(--q-dialog-swipe-x, 100vw));
6391
+ }
6392
+ to {
6393
+ opacity: 1;
6394
+ transform: none;
6395
+ }
6396
+ }
6397
+
6398
+ @keyframes q-dialog-swipe-out {
6399
+ from {
6400
+ opacity: 1;
6401
+ transform: none;
6402
+ }
6403
+ to {
6404
+ opacity: 0;
6405
+ transform: translateX(var(--q-dialog-swipe-x, 100vw));
6406
+ }
6407
+ }
6408
+
6240
6409
  /* ===== QContainer ===== */
6241
6410
  .q-container {
6242
6411
  width: 100%;
@@ -6269,11 +6438,80 @@ html.dark body {
6269
6438
  z-index: 0;
6270
6439
  pointer-events: none;
6271
6440
  }
6272
- .q-container--bg > :not(.q-container__bg) {
6441
+ .q-container--bg > :not(.q-container__bg, .q-container__img) {
6273
6442
  position: relative;
6274
6443
  z-index: 1;
6275
6444
  }
6276
6445
 
6446
+ /* — image de fond (prop background-image) : couche cover derrière le contenu — */
6447
+ .q-container__img {
6448
+ position: absolute;
6449
+ inset: 0;
6450
+ z-index: 0;
6451
+ width: 100%;
6452
+ height: 100%;
6453
+ object-fit: var(--q-container-img-fit, cover);
6454
+ pointer-events: none;
6455
+ user-select: none;
6456
+ }
6457
+
6458
+ /* taille CSS libre ("50%", "400px"…) : boîte centrée (translate séparé de
6459
+ transform → compose avec le Ken Burns), image entière visible */
6460
+ .q-container__img--sized {
6461
+ width: var(--q-container-img-size);
6462
+ height: var(--q-container-img-size);
6463
+ left: 50%;
6464
+ top: 50%;
6465
+ translate: -50% -50%;
6466
+ object-fit: contain;
6467
+ }
6468
+
6469
+ /* glassmorphisée : floutée + saturée + léger zoom pour masquer les bords du blur */
6470
+ .q-container__img--glass {
6471
+ filter: blur(14px) saturate(1.4);
6472
+ transform: scale(1.15);
6473
+ }
6474
+
6475
+ /* — Ken Burns indéterminé (prop background-animated) : zoom + panoramique
6476
+ lents qui bouclent — direction et durée configurables (défaut alternate 24s) */
6477
+ .q-container__img--animated {
6478
+ animation:
6479
+ q-container-kenburns var(--q-container-kenburns-duration, 24s) ease-in-out
6480
+ var(--q-container-kenburns-direction, alternate) infinite;
6481
+ will-change: transform;
6482
+ }
6483
+ @keyframes q-container-kenburns {
6484
+ 0% {
6485
+ transform: scale(1.06) translate(0%, 0%);
6486
+ }
6487
+ 30% {
6488
+ transform: scale(1.18) translate(-2%, -1.5%);
6489
+ }
6490
+ 60% {
6491
+ transform: scale(1.14) translate(2%, 1.5%);
6492
+ }
6493
+ 100% {
6494
+ transform: scale(1.22) translate(-1%, 2%);
6495
+ }
6496
+ }
6497
+
6498
+ /* — glassmorphism du conteneur (prop glass) : fond translucide + flou de ce
6499
+ qui est derrière + bordure claire (variables personnalisables) — */
6500
+ .q-container--glass {
6501
+ --q-container-glass-bg: rgb(255 255 255 / 0.14);
6502
+ --q-container-glass-border: rgb(255 255 255 / 0.3);
6503
+ --q-container-glass-blur: 14px;
6504
+ background-color: var(--q-container-glass-bg);
6505
+ border: 1px solid var(--q-container-glass-border);
6506
+ -webkit-backdrop-filter: blur(var(--q-container-glass-blur)) saturate(1.4);
6507
+ backdrop-filter: blur(var(--q-container-glass-blur)) saturate(1.4);
6508
+ box-shadow: 0 8px 32px rgb(0 0 0 / 0.12);
6509
+ }
6510
+ .dark .q-container--glass {
6511
+ --q-container-glass-bg: rgb(255 255 255 / 0.06);
6512
+ --q-container-glass-border: rgb(255 255 255 / 0.14);
6513
+ }
6514
+
6277
6515
  /* grid : grille de carrés qui s'estompe vers les bords */
6278
6516
  .q-container__bg--grid {
6279
6517
  background-image:
@@ -6485,6 +6723,9 @@ html.dark body {
6485
6723
  .q-container__wave {
6486
6724
  animation: none;
6487
6725
  }
6726
+ .q-container__img--animated {
6727
+ animation: none;
6728
+ }
6488
6729
  }
6489
6730
 
6490
6731
  /* ===== QMarquee — bandeau défilant infini ===== */