import {
booleanAttribute,
ChangeDetectionStrategy,
Component,
computed,
inject,
input,
output,
} from '@angular/core';
import { AfricaniesUiI18n } from '../i18n/africanies-ui-i18n';
import { AfricaniesIconComponent } from '@africanies/africanies-icons';
import {
ActionMenuComponent,
ActionMenuTriggerDirective,
} from '../action-menu';
import type { AfricaniesMenuItem } from '../action-menu/menu-item';
import { ButtonComponent } from '../button/button.component';
import { flagCdnUrl } from './flag-cdn';
import type { LanguageSwitcherOption } from './language-switcher-option';
/**
* Compact language menu with circular flagcdn (or custom) flags on the trigger
* and each option row. Hosts own dictionaries and persistence; this only emits
* the selected code.
*
* @example
* ```html
*
* ```
*/
@Component({
selector: 'africanies-language-switcher',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
ActionMenuComponent,
ActionMenuTriggerDirective,
AfricaniesIconComponent,
ButtonComponent,
],
template: `
`,
})
/**
* Compact language menu with circular flag prefixes and an optional caret.
*/
export class LanguageSwitcherComponent {
private readonly i18n = inject(AfricaniesUiI18n);
protected readonly resolvedAriaLabel = computed(() => {
const label = this.ariaLabel();
return label === 'Language'
? this.i18n.t('africaniesUi.language.ariaLabel', 'Language')
: label;
});
/** Available languages (order preserved in the menu). */
readonly options = input.required();
/** Active language code. */
readonly value = input.required();
/** Accessible name for the trigger and menu. */
readonly ariaLabel = input('Language');
readonly disabled = input(false, { transform: booleanAttribute });
/**
* When true (default), show the active label beside the flag on `sm+`
* viewports. The flag always remains.
*/
readonly showLabel = input(true, { transform: booleanAttribute });
/** When true (default), show a chevron after the label. */
readonly showCaret = input(true, { transform: booleanAttribute });
/** Emits the chosen language code when the user picks a row. */
readonly valueChange = output();
protected readonly activeOption = computed(() => {
const code = this.value();
return this.options().find((option) => option.code === code) ?? null;
});
protected readonly activeFlagUrl = computed(() => {
const option = this.activeOption();
return option ? resolveFlagUrl(option) : null;
});
protected readonly activeLabel = computed(
() => this.activeOption()?.label ?? this.value(),
);
protected readonly menuItems = computed((): AfricaniesMenuItem[] =>
this.options().map((option) => ({
label: option.label,
imageUrl: resolveFlagUrl(option) ?? undefined,
imageShape: 'circle',
onClick: () => this.valueChange.emit(option.code),
})),
);
}
function resolveFlagUrl(option: LanguageSwitcherOption): string | null {
if (option.flagUrl) {
return option.flagUrl;
}
if (option.flagCountryCode) {
return flagCdnUrl(option.flagCountryCode);
}
return null;
}