diff --git a/src/app/features/compare/compare.component.scss b/src/app/features/compare/compare.component.scss index c19a372..da2ad55 100644 --- a/src/app/features/compare/compare.component.scss +++ b/src/app/features/compare/compare.component.scss @@ -86,8 +86,8 @@ &-value { flex: 1; min-width: 0; - font-size: 0.875rem; - font-weight: 700; + font-size: var(--dex-font-md); + font-weight: var(--dex-weight-bold); color: var(--dex-ink); white-space: nowrap; overflow: hidden; @@ -97,7 +97,7 @@ &-placeholder { flex: 1; min-width: 0; - font-size: 0.875rem; + font-size: var(--dex-font-md); color: var(--dex-text-muted); white-space: nowrap; overflow: hidden; @@ -124,8 +124,8 @@ cursor: pointer; color: var(--dex-text-muted); padding: 2px; - border-radius: 999px; - transition: color 0.15s ease, background 0.15s ease; + border-radius: var(--dex-radius-pill); + transition: color var(--dex-duration-fast) ease, background var(--dex-duration-fast) ease; mat-icon { font-size: 18px; @@ -190,10 +190,10 @@ justify-content: center; width: 44px; height: 44px; - border-radius: 50%; + border-radius: var(--dex-radius-circle); background: var(--pokedex-red); color: #fff; - font-size: 0.8125rem; + font-size: var(--dex-font-sm); font-weight: 900; letter-spacing: 0.04em; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35); @@ -233,8 +233,8 @@ } &__id { - font-size: 0.6875rem; - font-weight: 800; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-black); color: var(--dex-text-muted); letter-spacing: 0.04em; } @@ -244,7 +244,7 @@ color: var(--dex-ink); margin: 0; font-size: 1.0625rem; - font-weight: 800; + font-weight: var(--dex-weight-black); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -272,8 +272,8 @@ align-items: center; gap: 3px; color: var(--dex-text-muted); - font-size: 0.6875rem; - font-weight: 700; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-bold); } &__meta-icon { @@ -284,8 +284,8 @@ } &__section-title { - font-size: 0.75rem; - font-weight: 800; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-black); color: var(--dex-text-muted); text-transform: uppercase; letter-spacing: 0.06em; @@ -318,10 +318,10 @@ &__ability-pill { background: color-mix(in srgb, var(--dex-ink) 8%, transparent); color: var(--dex-ink); - font-size: 0.6875rem; - font-weight: 700; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-bold); padding: 5px 14px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); text-transform: capitalize; letter-spacing: 0.02em; } @@ -347,8 +347,8 @@ } p { - font-size: 0.875rem; - font-weight: 600; + font-size: var(--dex-font-md); + font-weight: var(--dex-weight-semibold); text-align: center; } } @@ -376,8 +376,8 @@ .compare-stat { padding: 5px 8px; - border-radius: 8px; - transition: background 0.15s ease; + border-radius: var(--dex-radius-md); + transition: background var(--dex-duration-fast) ease; &:hover { background: color-mix(in srgb, var(--dex-ink) 3%, transparent); @@ -390,8 +390,8 @@ } &__label { - font-size: 0.625rem; - font-weight: 800; + font-size: var(--dex-font-3xs); + font-weight: var(--dex-weight-black); color: var(--dex-text-muted); text-transform: uppercase; letter-spacing: 0.04em; @@ -418,8 +418,8 @@ &__bar { height: 8px; - border-radius: 999px; - transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1); + border-radius: var(--dex-radius-pill); + transition: width var(--dex-duration-slow) var(--dex-ease-standard); min-width: 4px; flex-shrink: 0; @@ -428,8 +428,8 @@ } &__value { - font-size: 0.6875rem; - font-weight: 800; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-black); color: var(--dex-ink); white-space: nowrap; flex-shrink: 0; @@ -502,7 +502,7 @@ } .compare__name { - font-size: 1.125rem; + font-size: var(--dex-font-lg); } .compare__sheet { @@ -511,12 +511,12 @@ } .compare-stat__label { - font-size: 0.6875rem; + font-size: var(--dex-font-2xs); min-width: 40px; } .compare-stat__value { - font-size: 0.75rem; + font-size: var(--dex-font-xs); min-width: 28px; } } diff --git a/src/app/features/pokemon-detail/pokemon-detail.component.scss b/src/app/features/pokemon-detail/pokemon-detail.component.scss index 49b7dc6..d2d57a5 100644 --- a/src/app/features/pokemon-detail/pokemon-detail.component.scss +++ b/src/app/features/pokemon-detail/pokemon-detail.component.scss @@ -62,7 +62,7 @@ pointer-events: none; z-index: 1; opacity: 0; - transition: opacity 0.4s ease; + transition: opacity var(--dex-duration-slow) ease; &--active { opacity: 1; @@ -106,11 +106,11 @@ justify-content: center; width: 44px; height: 44px; - border-radius: 50%; + border-radius: var(--dex-radius-circle); background: color-mix(in srgb, #fff 20%, transparent); color: #fff; text-decoration: none; - transition: background 0.15s ease; + transition: background var(--dex-duration-fast) ease; &:focus-visible { outline: 2px solid var(--dex-gold); @@ -164,8 +164,8 @@ &__id { display: block; color: rgba(255, 255, 255, 0.8); - font-weight: 800; - font-size: 0.875rem; + font-weight: var(--dex-weight-black); + font-size: var(--dex-font-md); letter-spacing: 0.04em; margin-bottom: 6px; } @@ -174,7 +174,7 @@ color: #fff; text-transform: capitalize; font-size: 1.75rem; - font-weight: 800; + font-weight: var(--dex-weight-black); line-height: 1.1; margin: 0 0 12px; } @@ -223,12 +223,12 @@ justify-content: center; width: 44px; height: 44px; - border-radius: 50%; + border-radius: var(--dex-radius-circle); border: none; background: color-mix(in srgb, var(--dex-ink) 10%, transparent); color: var(--dex-ink); cursor: pointer; - transition: background 0.15s ease; + transition: background var(--dex-duration-fast) ease; &:focus-visible { outline: 2px solid var(--dex-gold); @@ -263,7 +263,7 @@ backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid color-mix(in srgb, var(--dex-ink) 8%, transparent); - border-radius: 999px; + border-radius: var(--dex-radius-pill); padding: 6px 14px; box-shadow: var(--dex-shadow-lg), @@ -278,7 +278,7 @@ transform: translateY(-50%); width: 110px; height: 44px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); box-sizing: border-box; background: color-mix(in srgb, var(--dex-ink) 10%, transparent); box-shadow: var(--dex-shadow-sm); @@ -305,11 +305,11 @@ gap: 0; padding: 0; border: none; - border-radius: 999px; + border-radius: var(--dex-radius-pill); background: transparent; color: var(--dex-text-muted); font-size: 0.6rem; - font-weight: 800; + font-weight: var(--dex-weight-black); width: 48px; height: 44px; box-sizing: border-box; @@ -372,8 +372,8 @@ &__category { color: var(--dex-text-muted); - font-size: 0.75rem; - font-weight: 800; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-black); text-transform: uppercase; letter-spacing: 0.06em; text-align: center; @@ -382,7 +382,7 @@ &__description { color: var(--dex-ink); - font-size: 0.875rem; + font-size: var(--dex-font-md); line-height: 1.6; text-align: center; margin: 0 0 24px; @@ -399,9 +399,9 @@ &__badge { display: inline-flex; padding: 4px 14px; - border-radius: 999px; - font-size: 0.6875rem; - font-weight: 800; + border-radius: var(--dex-radius-pill); + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-black); text-transform: uppercase; letter-spacing: 0.05em; @@ -422,8 +422,8 @@ align-items: center; gap: 12px; padding: 10px 12px; - border-radius: 8px; - transition: background 0.15s ease; + border-radius: var(--dex-radius-md); + transition: background var(--dex-duration-fast) ease; &:nth-child(odd) { background: color-mix(in srgb, var(--dex-ink) 3%, transparent); @@ -432,8 +432,8 @@ &__about-label { color: var(--dex-text-muted); - font-size: 0.75rem; - font-weight: 700; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-bold); min-width: 100px; flex-shrink: 0; letter-spacing: 0.02em; @@ -441,15 +441,15 @@ &__about-value { color: var(--dex-ink); - font-size: 0.8125rem; - font-weight: 700; + font-size: var(--dex-font-sm); + font-weight: var(--dex-weight-bold); } &__section-title { text-align: center; margin: 0 0 12px; - font-size: 0.8125rem; - font-weight: 800; + font-size: var(--dex-font-sm); + font-weight: var(--dex-weight-black); text-transform: uppercase; letter-spacing: 0.04em; color: var(--dex-text-muted); @@ -477,10 +477,10 @@ &__ability-pill { background: color-mix(in srgb, var(--dex-ink) 8%, transparent); color: var(--dex-ink); - font-size: 0.75rem; - font-weight: 700; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-bold); padding: 6px 16px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); letter-spacing: 0.02em; } @@ -544,7 +544,7 @@ padding: 12px; min-width: 100px; border-radius: 12px; - transition: transform 0.15s ease, background 0.15s ease; + transition: transform var(--dex-duration-fast) ease, background var(--dex-duration-fast) ease; &:hover { transform: translateY(-3px); @@ -559,8 +559,8 @@ &__evo-id { color: var(--dex-text-muted); - font-size: 0.625rem; - font-weight: 800; + font-size: var(--dex-font-3xs); + font-weight: var(--dex-weight-black); letter-spacing: 0.03em; } @@ -596,19 +596,19 @@ &__evo-name { color: var(--dex-text); - font-weight: 800; + font-weight: var(--dex-weight-black); text-transform: capitalize; - font-size: 0.8125rem; + font-size: var(--dex-font-sm); } &__evo-method { color: var(--dex-text-muted); - font-size: 0.625rem; - font-weight: 700; + font-size: var(--dex-font-3xs); + font-weight: var(--dex-weight-bold); text-align: center; background: color-mix(in srgb, var(--dex-ink) 6%, transparent); padding: 2px 8px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); } } @@ -617,8 +617,8 @@ align-items: center; gap: 8px; padding: 6px 8px; - border-radius: 8px; - transition: background 0.15s ease; + border-radius: var(--dex-radius-md); + transition: background var(--dex-duration-fast) ease; &:hover { background: color-mix(in srgb, var(--dex-ink) 3%, transparent); @@ -634,8 +634,8 @@ &__label { color: var(--dex-text-muted); - font-size: 0.6875rem; - font-weight: 700; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-bold); text-align: left; letter-spacing: 0.03em; min-width: 80px; @@ -644,7 +644,7 @@ &__track { flex: 1; height: 8px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); background: color-mix(in srgb, var(--dex-ink) 10%, transparent); overflow: hidden; } @@ -652,14 +652,14 @@ &__fill { display: block; height: 100%; - border-radius: 999px; + border-radius: var(--dex-radius-pill); transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1); } &__value { color: var(--dex-ink); - font-size: 0.875rem; - font-weight: 800; + font-size: var(--dex-font-md); + font-weight: var(--dex-weight-black); min-width: 28px; text-align: right; } @@ -667,11 +667,11 @@ &__ev { font-size: 0.5625rem; color: var(--dex-gold); - font-weight: 800; + font-weight: var(--dex-weight-black); white-space: nowrap; background: color-mix(in srgb, var(--dex-gold) 12%, transparent); padding: 1px 6px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); } &--total { @@ -719,7 +719,7 @@ display: block; width: 44px; height: 44px; - border-radius: 50%; + border-radius: var(--dex-radius-circle); background: color-mix(in srgb, var(--dex-text-muted) 15%, transparent); } @@ -743,7 +743,7 @@ &__tab { width: 70px; height: 18px; - border-radius: 4px; + border-radius: var(--dex-radius-sm); background: color-mix(in srgb, var(--dex-text-muted) 12%, transparent); } @@ -812,14 +812,14 @@ h2 { margin: 0; font-size: 1.1rem; - font-weight: 800; + font-weight: var(--dex-weight-black); color: var(--dex-ink); } p { margin: 0; color: var(--dex-text-muted); - font-size: 0.8125rem; + font-size: var(--dex-font-sm); } .dex-back { @@ -839,13 +839,13 @@ flex-direction: column; gap: 6px; padding: 8px 12px; - border-radius: 8px; + border-radius: var(--dex-radius-md); background: color-mix(in srgb, var(--dex-ink) 3%, transparent); } .pdetail__type-chart-group-label { - font-size: 0.6875rem; - font-weight: 800; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-black); color: var(--dex-text-muted); text-transform: uppercase; letter-spacing: 0.04em; @@ -868,7 +868,7 @@ .pdetail__move-summary { margin-bottom: 16px; padding: 16px; - border-radius: 8px; + border-radius: var(--dex-radius-md); background: color-mix(in srgb, var(--dex-ink) 3%, transparent); &-row { @@ -883,8 +883,8 @@ gap: 2px; strong { - font-size: 1.125rem; - font-weight: 800; + font-size: var(--dex-font-lg); + font-weight: var(--dex-weight-black); color: var(--dex-ink); line-height: 1.2; } @@ -894,7 +894,7 @@ align-items: center; gap: 2px; font-size: 0.5625rem; - font-weight: 800; + font-weight: var(--dex-weight-black); color: var(--dex-text-muted); text-transform: uppercase; letter-spacing: 0.04em; @@ -914,8 +914,8 @@ } &-label { - font-size: 0.625rem; - font-weight: 800; + font-size: var(--dex-font-3xs); + font-weight: var(--dex-weight-black); color: var(--dex-gold); text-transform: uppercase; letter-spacing: 0.04em; @@ -934,20 +934,20 @@ align-items: center; gap: 6px; padding: 4px 10px; - border-radius: 8px; + border-radius: var(--dex-radius-md); background: color-mix(in srgb, var(--dex-gold) 14%, transparent); } &-name { - font-size: 0.6875rem; - font-weight: 700; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-bold); color: var(--dex-ink); text-transform: capitalize; } &-power { - font-size: 0.75rem; - font-weight: 800; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-black); color: var(--dex-gold); } } @@ -959,7 +959,7 @@ } .pdetail__move-group { - border-radius: 8px; + border-radius: var(--dex-radius-md); background: color-mix(in srgb, var(--dex-ink) 3%, transparent); overflow: hidden; @@ -968,8 +968,8 @@ align-items: center; justify-content: space-between; padding: 10px 12px; - font-size: 0.75rem; - font-weight: 800; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-black); color: var(--dex-ink); text-transform: uppercase; letter-spacing: 0.04em; @@ -986,12 +986,12 @@ } &-count { - font-size: 0.625rem; - font-weight: 700; + font-size: var(--dex-font-3xs); + font-weight: var(--dex-weight-bold); color: var(--dex-text-muted); background: color-mix(in srgb, var(--dex-ink) 8%, transparent); padding: 2px 8px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); } &-grid { @@ -1004,7 +1004,7 @@ .pdetail__move-card { padding: 10px 12px; - border-radius: 8px; + border-radius: var(--dex-radius-md); background: var(--dex-bg); overflow: hidden; @@ -1018,8 +1018,8 @@ } &-name { - font-size: 0.75rem; - font-weight: 700; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-bold); color: var(--dex-ink); text-transform: capitalize; overflow: hidden; @@ -1049,14 +1049,14 @@ } &-stat-value { - font-size: 0.6875rem; - font-weight: 700; + font-size: var(--dex-font-2xs); + font-weight: var(--dex-weight-bold); color: var(--dex-ink); } &-stat-label { font-size: 0.5rem; - font-weight: 800; + font-weight: var(--dex-weight-black); color: var(--dex-text-muted); text-transform: uppercase; letter-spacing: 0.04em; diff --git a/src/app/features/pokemon-list/pokemon-list.component.scss b/src/app/features/pokemon-list/pokemon-list.component.scss index b8f2610..a1f480e 100644 --- a/src/app/features/pokemon-list/pokemon-list.component.scss +++ b/src/app/features/pokemon-list/pokemon-list.component.scss @@ -26,14 +26,14 @@ height: 44px; padding: 0 18px; border: 2px solid color-mix(in srgb, var(--dex-ink) 12%, transparent); - border-radius: 999px; + border-radius: var(--dex-radius-pill); background: var(--dex-bg); color: var(--dex-ink); cursor: pointer; font: inherit; - font-size: 0.8125rem; - font-weight: 700; - transition: border-color 0.15s ease, background 0.2s ease; + font-size: var(--dex-font-sm); + font-weight: var(--dex-weight-bold); + transition: border-color var(--dex-duration-fast) ease, background 0.2s ease; &:hover { border-color: var(--dex-gold); @@ -60,11 +60,11 @@ right: -4px; background: var(--pokedex-red); color: #fff; - font-size: 0.625rem; - font-weight: 800; + font-size: var(--dex-font-3xs); + font-weight: var(--dex-weight-black); min-width: 16px; height: 16px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); display: flex; align-items: center; justify-content: center; @@ -102,12 +102,12 @@ align-items: center; gap: 4px; padding: 6px 14px; - border-radius: 999px; + border-radius: var(--dex-radius-pill); border: none; background: color-mix(in srgb, var(--type-color) 65%, white); color: #fff; - font-size: 0.75rem; - font-weight: 700; + font-size: var(--dex-font-xs); + font-weight: var(--dex-weight-bold); cursor: pointer; transition: all 0.2s ease; text-shadow: 0 1px 2px color-mix(in srgb, #000 20%, transparent); @@ -211,8 +211,8 @@ gap: 8px; padding: 20px 16px; color: var(--dex-text-muted); - font-size: 0.8125rem; - font-weight: 600; + font-size: var(--dex-font-sm); + font-weight: var(--dex-weight-semibold); } .pokemon-list__loading-more-icon { @@ -241,14 +241,14 @@ &-text { color: var(--dex-text-muted); - font-size: 1rem; - font-weight: 700; + font-size: var(--dex-font-base); + font-weight: var(--dex-weight-bold); margin: 0 0 4px; } &-hint { color: var(--dex-text-muted); - font-size: 0.8125rem; + font-size: var(--dex-font-sm); opacity: 0.7; margin: 0; } @@ -272,8 +272,8 @@ p { color: var(--dex-text-muted); - font-size: 0.875rem; - font-weight: 600; + font-size: var(--dex-font-md); + font-weight: var(--dex-weight-semibold); margin: 0; } } @@ -285,7 +285,7 @@ z-index: 20; width: 44px; height: 44px; - border-radius: 50%; + border-radius: var(--dex-radius-circle); border: none; background: var(--pokedex-red); color: #fff; @@ -321,7 +321,7 @@ align-items: flex-end; justify-content: center; overflow: hidden; - transition: height 0.15s ease; + transition: height var(--dex-duration-fast) ease; height: 0; mat-icon { @@ -330,7 +330,7 @@ width: 24px; height: 24px; margin-bottom: 4px; - transition: transform 0.15s ease; + transition: transform var(--dex-duration-fast) ease; } &--visible { diff --git a/src/app/features/team/team.component.html b/src/app/features/team/team.component.html index e33f6c9..684f7c9 100644 --- a/src/app/features/team/team.component.html +++ b/src/app/features/team/team.component.html @@ -282,18 +282,6 @@

Cobertura de tipos

} - @if (pickerOpen()) { - - } @if (confirmRemoveId(); as id) { - -
- - -
- } -} @else { -
- -
-} - - +
} - @if (!modal() && (title() || hint())) { + @if (title() || hint()) {
@if (title()) {

{{ title() }}

@@ -149,4 +121,4 @@

{{ title() }}

}
} - +
diff --git a/src/app/shared/components/pokemon-picker/pokemon-picker.component.scss b/src/app/shared/components/pokemon-picker/pokemon-picker.component.scss index b022725..becb743 100644 --- a/src/app/shared/components/pokemon-picker/pokemon-picker.component.scss +++ b/src/app/shared/components/pokemon-picker/pokemon-picker.component.scss @@ -6,8 +6,12 @@ width: 100%; } -:host.pp--modal { - display: contents; +// Usado dentro de PokemonPickerDialogComponent: o picker preenche o espaço +// restante da coluna flex do diálogo, em vez de ser um dropdown flutuante. +:host.pp--expanded { + display: flex; + flex-direction: column; + min-height: 0; } .pp-root { @@ -40,44 +44,14 @@ max-height: 60vh; } -.pp--modal { - .pp-panel { - position: static; - flex: 1 1 auto; - min-height: 0; - border: none; - border-radius: 0; - box-shadow: none; - padding: 0; - } -} - -.pp-overlay { - position: fixed; - inset: 0; - z-index: 200; - background: rgba(0, 0, 0, 0.45); - display: flex; - align-items: center; - justify-content: center; - padding: 16px; - box-sizing: border-box; -} - -.pp-dialog { - width: 100%; - max-width: 480px; - // dvh (não vh) evita que o diálogo seja cortado quando a barra de - // endereço do navegador mobile aparece/some (ex.: Safari iOS). - max-height: 80dvh; - display: flex; - flex-direction: column; - gap: 12px; - background: var(--dex-bg); - border-radius: 20px; - box-shadow: var(--dex-shadow-xl); - padding: 16px; - box-sizing: border-box; +:host.pp--expanded .pp-panel { + position: static; + flex: 1 1 auto; + min-height: 0; + border: none; + border-radius: 0; + box-shadow: none; + padding: 0; } .pp-head { @@ -87,7 +61,7 @@ gap: 12px; } -:host:not(.pp--modal) .pp-root > .pp-head { +.pp-root > .pp-head { flex-direction: column; } diff --git a/src/app/shared/components/pokemon-picker/pokemon-picker.component.ts b/src/app/shared/components/pokemon-picker/pokemon-picker.component.ts index 0b2d326..b9b60ee 100644 --- a/src/app/shared/components/pokemon-picker/pokemon-picker.component.ts +++ b/src/app/shared/components/pokemon-picker/pokemon-picker.component.ts @@ -1,4 +1,3 @@ -import { NgTemplateOutlet } from '@angular/common'; import { Component, computed, effect, ElementRef, HostListener, inject, input, output, signal, ViewChild } from '@angular/core'; import { MatIconModule } from '@angular/material/icon'; import { MatTooltipModule } from '@angular/material/tooltip'; @@ -15,23 +14,30 @@ import { IconButtonComponent } from '../icon-button/icon-button.component'; const ATTACKING_TYPES = Object.keys(TYPE_CHART); +/** + * Busca/autocomplete de Pokémon. Uso padrão: dropdown inline sobre o campo + * de busca (ex.: compare). Para uso como diálogo modal, ver + * `PokemonPickerDialogComponent` — este componente não sabe mais nada sobre + * overlay/modal, só sobre "estou expandido preenchendo o espaço do meu pai + * ou sou um dropdown flutuante" (`alwaysOpen`). + */ @Component({ selector: 'app-pokemon-picker', standalone: true, - imports: [NgTemplateOutlet, MatIconModule, MatTooltipModule, TypeBadgeComponent, LoadingSpinnerComponent, IconButtonComponent], + imports: [MatIconModule, MatTooltipModule, TypeBadgeComponent, LoadingSpinnerComponent, IconButtonComponent], templateUrl: './pokemon-picker.component.html', styleUrl: './pokemon-picker.component.scss', host: { - '[class.pp--modal]': 'modal()', + '[class.pp--expanded]': 'alwaysOpen()', }, }) export class PokemonPickerComponent { private pokemonService = inject(PokemonService); - /** Modo de exibição. Default: dropdown (autocomplete inline). true = popup modal centralizado. */ - modal = input(false); - /** Força a abertura do dropdown a partir do pai (ex.: escolha de slot no time). */ - open = input(false); + /** Mantém a lista de resultados sempre visível, em vez de só ao focar/digitar + * (uso: dentro de `PokemonPickerDialogComponent`, onde o painel é o próprio + * conteúdo do diálogo, não um dropdown flutuante). */ + alwaysOpen = input(false); /** Valor exibido no campo quando o usuário não está digitando (ex.: Pokémon já escolhido). */ value = input(''); /** IDs que não devem aparecer na lista (ex.: os que já estão no time). */ @@ -69,7 +75,7 @@ export class PokemonPickerComponent { /** Abre ao focar/digitar (uso como autocomplete). */ show = signal(false); fieldFocused = signal(false); - panelVisible = computed(() => this.show() || this.open()); + panelVisible = computed(() => this.show() || this.alwaysOpen()); @ViewChild('root') root?: ElementRef; @ViewChild('searchInput') searchInput?: ElementRef; @@ -91,19 +97,12 @@ export class PokemonPickerComponent { constructor() { this.loadData(); + // Seed único na criação (não um effect): cada instância nasce e morre + // com uma "sessão" de busca — não deve resetar o filtro do usuário se + // o pai re-renderizar com o mesmo array por outro motivo. + this.typeFilter.set(this.preselectTypes()); effect(() => { - if (this.modal()) { - if (this.open()) { - this.resetForOpen(); - } - } else if (!this.open()) { - this.show.set(false); - } - }); - - effect(() => { - if (this.modal()) return; const v = this.value(); if (v && !this.fieldFocused()) { this.query.set(v); @@ -111,22 +110,15 @@ export class PokemonPickerComponent { }); } - private resetForOpen(): void { - this.filtersOpen.set(false); - this.typeFilter.set(this.preselectTypes()); - this.show.set(true); - setTimeout(() => this.searchInput?.nativeElement?.focus(), 0); - } - onQueryInput(value: string): void { this.query.set(value); - if (!this.modal()) this.show.set(true); + this.show.set(true); this.queryChange.emit(value); } onFocus(): void { this.fieldFocused.set(true); - if (!this.modal()) this.show.set(true); + this.show.set(true); } onBlur(): void { @@ -169,22 +161,21 @@ export class PokemonPickerComponent { dismiss(): void { this.show.set(false); - if (this.open()) { - this.dismissed.emit(); - } + this.dismissed.emit(); } @HostListener('document:pointerdown', ['$event']) onGlobalClick(event: PointerEvent): void { - if (this.modal()) return; - if ((this.show() || this.open()) && this.root && !this.root.nativeElement.contains(event.target as Node)) { + if (this.alwaysOpen()) return; + if (this.show() && this.root && !this.root.nativeElement.contains(event.target as Node)) { this.dismiss(); } } @HostListener('document:keydown.escape') onEscape(): void { - if (this.show() || this.open()) { + if (this.alwaysOpen()) return; + if (this.show()) { this.dismiss(); } } @@ -200,4 +191,4 @@ export class PokemonPickerComponent { paddedId(id: number): string { return formatPokemonId(id); } -} \ No newline at end of file +} diff --git a/src/styles.scss b/src/styles.scss index 0238a0f..d330625 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -127,6 +127,29 @@ app-root { } } +// Diálogo do picker de Pokémon (ver PokemonPickerDialogComponent): a casca +// comportamental (focus trap, Escape, clique fora, aria-modal, animação) é +// do MatDialog; o card visual continua 100% controlado pelo componente — +// aqui só neutralizamos o container/surface padrão do Material pra não +// sobrepor esse visual com o dele (mesmo padrão do .app-snackbar acima). +.pp-dialog-panel { + .mat-mdc-dialog-container, + .mdc-dialog__surface, + .mat-mdc-dialog-surface { + background: transparent !important; + box-shadow: none !important; + border-radius: 0 !important; + padding: 0 !important; + overflow: visible; + } +} + +// Mesma cor do antigo .pp-overlay hand-rolled (o backdrop escuro padrão do +// CDK é mais claro). +.pp-dialog-backdrop { + background: rgba(0, 0, 0, 0.45); +} + @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important;