-
Notifications
You must be signed in to change notification settings - Fork 4
feat: add presentational country flag component and docs (#DS-1405) #1711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
e2e489d
feat: add presentational country flag component and docs (#DS-1405)
NikGurev 1c3fbdd
refactor(flag): simplify API and rework examples (#DS-1405)
NikGurev b0a4559
refactor(flag): use inline svg in examples and simplify overview (#DS…
NikGurev 6f72899
chore: review docs, use direct icons instead pipe
NikGurev 1f04f95
test: updated e2e snapshots
NikGurev 2bf7c81
chore: update e2e
NikGurev c7608a8
test: updated e2e snapshots
NikGurev b631004
chore: after review
NikGurev 939465d
refactor(flag): drop hardcoded stylized, make aspect
NikGurev 6c714e4
refactor(flag): returned back text
NikGurev 119039e
test: updated e2e snapshots
NikGurev af3d09a
docs(flag): improve russian article wording (#DS-1405)
rmnturov 2244e09
refactor: removed redundant from example
NikGurev ebc4713
chore: revert screenshots update
NikGurev 0072e9d
fix(flag): correct wikimedia commons spelling in russian article (#DS…
rmnturov b1e50b8
chore: fix linter
NikGurev 5800cd5
chore: fix linter
NikGurev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { bootstrapApplication } from '@angular/platform-browser'; | ||
| import { provideAnimations } from '@angular/platform-browser/animations'; | ||
| import { DevApp } from './module'; | ||
|
|
||
| bootstrapApplication(DevApp, { | ||
| providers: [ | ||
| provideAnimations() | ||
| ] | ||
| }).catch((error) => console.error(error)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core'; | ||
| import { FlagExamplesModule } from '../../docs-examples/components/flag'; | ||
| import { DevThemeToggle } from '../theme-toggle'; | ||
|
|
||
| @Component({ | ||
| selector: 'dev-examples', | ||
| imports: [FlagExamplesModule], | ||
| template: ` | ||
| <flag-aspect-ratio-example /> | ||
| <flag-square-example /> | ||
| <flag-overview-example /> | ||
| <flag-language-example /> | ||
| <flag-fallback-example /> | ||
| <flag-stylized-example /> | ||
| <flag-circle-example /> | ||
| <flag-sizes-example /> | ||
| `, | ||
| changeDetection: ChangeDetectionStrategy.OnPush | ||
| }) | ||
| export class DevDocsExamples {} | ||
|
|
||
| @Component({ | ||
| selector: 'dev-app', | ||
| imports: [DevDocsExamples, DevThemeToggle], | ||
| template: ` | ||
| <dev-theme-toggle /> | ||
| <dev-examples /> | ||
| `, | ||
| changeDetection: ChangeDetectionStrategy.OnPush, | ||
| encapsulation: ViewEncapsulation.None | ||
| }) | ||
| export class DevApp {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "extends": "../tsconfig.json", | ||
| "include": ["**/*.d.ts"], | ||
| "files": ["main.ts"] | ||
| } |
|
NikGurev marked this conversation as resolved.
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { expect, Page, test } from '@playwright/test'; | ||
| import { e2eEnableDarkTheme } from 'packages/e2e/utils'; | ||
|
|
||
| test.describe('KbqFlagModule', () => { | ||
| test.describe('E2eFlagStyles', () => { | ||
| const getComponent = (page: Page) => page.getByTestId('e2eFlagStyles'); | ||
|
|
||
| test('styles', async ({ page }) => { | ||
| await page.goto('/E2eFlagStyles'); | ||
| await expect(getComponent(page)).toHaveScreenshot('01-light.png'); | ||
| await e2eEnableDarkTheme(page); | ||
| await expect(getComponent(page)).toHaveScreenshot('01-dark.png'); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; | ||
| import { DomSanitizer } from '@angular/platform-browser'; | ||
| import { KbqFlagModule, KbqFlagShape } from '@koobiq/components/flag'; | ||
|
|
||
| // A minimal inline SVG (Norway-like) is enough to exercise shape/shadow decoration without | ||
| // depending on a flag data package in the e2e app. | ||
| const sampleFlag = `<svg viewBox="0 0 22 16" xmlns="http://www.w3.org/2000/svg"> | ||
| <rect width="22" height="16" fill="#ef2b2d" /> | ||
| <rect x="6" width="4" height="16" fill="#fff" /> | ||
| <rect y="6" width="22" height="4" fill="#fff" /> | ||
| <rect x="7" width="2" height="16" fill="#002868" /> | ||
| <rect y="7" width="22" height="2" fill="#002868" /> | ||
| </svg>`; | ||
|
|
||
| @Component({ | ||
| selector: 'e2e-flag-styles', | ||
| imports: [KbqFlagModule], | ||
| template: ` | ||
| <div> | ||
| @for (shape of shapes; track shape) { | ||
| <kbq-flag [shape]="shape" [innerHTML]="flag" /> | ||
| } | ||
| </div> | ||
| <div> | ||
| <kbq-flag shadow="none" [innerHTML]="flag" /> | ||
| <kbq-flag shadow="inset" [innerHTML]="flag" /> | ||
| <kbq-flag empty /> | ||
| </div> | ||
| `, | ||
| styles: ` | ||
| :host { | ||
| display: inline-flex; | ||
| flex-direction: column; | ||
| gap: var(--kbq-size-l); | ||
| padding: var(--kbq-size-l); | ||
| font-size: 48px; | ||
| } | ||
|
|
||
| :host > div { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: var(--kbq-size-l); | ||
| } | ||
| `, | ||
| changeDetection: ChangeDetectionStrategy.OnPush, | ||
| host: { | ||
| 'data-testid': 'e2eFlagStyles' | ||
| } | ||
| }) | ||
| export class E2eFlagStyles { | ||
| private readonly sanitizer = inject(DomSanitizer); | ||
| protected readonly flag = this.sanitizer.bypassSecurityTrustHtml(sampleFlag); | ||
| protected readonly shapes: KbqFlagShape[] = ['rectangle', 'square', 'circle']; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| <div class="kbq-callout kbq-callout_theme"> | ||
| <div class="kbq-callout__header">Note</div> | ||
| <div class="kbq-callout__content kbq-docs-element-last-child-margin-bottom-0"> | ||
|
|
||
| Use the [country-flag-icons](https://www.npmjs.com/package/country-flag-icons) package to show a small country flag in your product: | ||
|
|
||
| ```bash | ||
| npm install country-flag-icons | ||
| ``` | ||
|
|
||
| </div> | ||
| </div> | ||
|
|
||
| - **Full ISO 3166-1 coverage**. Every existing country is identified by a two-letter code (RU, DE, FR). | ||
| - **Flags are redrawn for small sizes**. Most sets take detailed SVGs from Wikimedia Commons, and at interface sizes (16—24 px) the small coats of arms, inscriptions and emblems on them become illegible. In country-flag-icons the details are simplified, so flags stay recognizable even at icon size. | ||
| - Actively maintained, MIT licensed. | ||
|
|
||
| ## Aspect ratio | ||
|
|
||
| By default flags use a 3:2 ratio. This is the primary format — use it in most scenarios: inline with text, lists, selects. Flags with a different ratio (e.g. 4:3) or from other sources are supported by overriding the `--kbq-flag-aspect-ratio` CSS variable. | ||
|
|
||
| <!-- example(flag-aspect-ratio) --> | ||
|
|
||
| Square flags live in a separate subpackage and are needed where the 3:2 format does not fit: avatar selectors, compact circles, dense grids. | ||
|
|
||
| Most 1:1 versions are a center crop of the 3:2 flag. For flags that lose meaning when cropped this way, the package ships dedicated square variants (e.g. EU and KR) — they are substituted automatically from the same subpackage. | ||
|
|
||
| <!-- example(flag-square) --> | ||
|
|
||
| ## Inset shadow: separating from the background | ||
|
|
||
| Flags get a thin inset shadow (an inset outline) along the edge. Without it a flag blends into the background: | ||
|
|
||
| - lots of white: the flag blends into the light page background. | ||
| - some flags contain black or dark colors: they blend into the background in the dark theme. | ||
|
|
||
| That is why the shadow color depends on the theme: in the light theme the shadow is dark, in the dark theme it lightens or is removed. The shadow is implemented as an inset box-shadow on a pseudo-element over the flag, and its color comes from a CSS variable that switches together with the theme. | ||
|
|
||
| <!-- example(flag-overview) --> | ||
|
|
||
| ## A flag is not a language | ||
|
|
||
| A flag denotes a country or region, not a language. Do not use a flag to pick an interface language: one language is spoken in several countries (Spanish is not only Spain), and one country may have several languages. | ||
|
|
||
| <!-- example(flag-language) --> | ||
|
|
||
| ## When the flag is missing | ||
|
|
||
| First check availability via `hasFlag(code)` and do not render an empty gap: | ||
|
|
||
| ```ts | ||
| import { hasFlag } from 'country-flag-icons'; | ||
|
|
||
| hasFlag('RU'); // true | ||
| hasFlag('ZZ'); // false | ||
| ``` | ||
|
|
||
| Then it depends on the situation. | ||
|
|
||
| **Unknown or invalid code.** Show a neutral placeholder (a gray rectangle, square, circle or a globe icon). Empty space is acceptable only if it does not break the layout. | ||
|
|
||
| <!-- example(flag-fallback) --> | ||
|
|
||
| **You need a non-country flag** (organization, historical or disputed territory, federal subject). Do not add it to the country-flag-icons package. Add it to your internal set so that the way it is used does not change. | ||
|
|
||
| **Supranational flags.** The EU flag is available as a separate 1:1 version; for the rest (ASEAN, UN, etc.) create your own images in the project. | ||
|
|
||
| **It is a real country, but the flag really is missing.** This is unlikely — the ISO 3166-1 standard is fully covered — but first update the package version. If the flag is outdated or missing, open an issue or PR in the package repository, and temporarily use your own image in your project. | ||
|
|
||
| **You need to show the flag at a large size.** In the package the flags are redrawn and simplified for small sizes. To show them at a large size you need flags in their original detail — use a third-party package. In most sources flags are provided without redrawing. | ||
|
|
||
| ## Accessibility | ||
|
|
||
| If the flag carries meaning (for example, it is the only indicator of the selected country), pass a text caption: | ||
|
|
||
| ```html | ||
| <kbq-flag label="Germany"><img src="…/DE.svg" alt="" /></kbq-flag> | ||
| ``` | ||
|
|
||
| If there is already adjacent text (inline, option, block), the flag is decorative — mark it `decorative` so it is hidden from screen readers and does not duplicate the caption. | ||
|
|
||
| ```html | ||
| <kbq-flag decorative><img src="…/DE.svg" alt="" /></kbq-flag> | ||
| Germany | ||
| ``` | ||
|
|
||
| In short: a flag must always have a text alternative — either visible text next to it (then the flag is `decorative`), or a `label` caption for the screen reader (when there is no visible text). Only the third case is not allowed — when there is neither. | ||
|
|
||
| ## Examples | ||
|
|
||
| ### With shadow and volume | ||
|
|
||
| A gradient imitating folds is layered over the image; the flag is rounded and casts a shadow. | ||
|
|
||
| <!-- example(flag-stylized) --> | ||
|
|
||
| ### Circular flag | ||
|
|
||
| Use the 1:1 aspect ratio version. | ||
|
|
||
| <!-- example(flag-circle) --> | ||
|
|
||
| ### Integer sizes | ||
|
|
||
| Choose a flag size whose dimensions are multiples of a pixel — otherwise the image edges will be blurry. | ||
|
|
||
| <!-- example(flag-sizes) --> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.