solid-circle-flags
Version:
A Solid component with a collection of 300+ minimal circular SVG country flags.
348 lines (342 loc) • 6.87 kB
JavaScript
import { createComponent, mergeProps, memo, spread, effect, setAttribute, template } from 'solid-js/web';
import { createSignal } from 'solid-js';
// src/index.tsx
// src/countries.ts
var countryToCountryMap = {
ac: "sh-ac",
bq: "bq-bo",
bv: "no",
"cn-hk": "hk",
cp: "fr-cp",
dg: "io",
ea: "es-ce",
eu: "european_union",
fx: "fr",
hm: "au",
ic: "es-cn",
sh: "sh-hl",
sj: "no",
su: "soviet_union",
ta: "sh-ta",
uk: "gb",
um: "us",
"us-as": "as",
"us-gu": "gu",
"us-mp": "mp",
"us-pr": "pr",
"us-um": "us",
"us-vi": "vi"
};
// src/languages.ts
var languageToCountryMap = {
aa: "et-af",
ab: "ge-ab",
af: "za",
ak: "gh",
am: "et",
an: "es-ar",
as: "in-as",
av: "ru-da",
ay: "bo",
az: "az",
ba: "ru-ba",
be: "by",
bg: "bg",
bi: "vu",
bm: "ml",
bn: "bd",
bo: "tibet",
br: "fr-bre",
bs: "ba",
ca: "es-ct",
ce: "ru-ce",
ceb: "ph",
ch: "gu",
chm: "ru",
ckb: "iq-kr",
co: "fr-20r",
cs: "cz",
cv: "ru-cu",
cy: "gb-wls",
da: "dk",
de: "de",
dv: "mv",
dz: "bt",
ee: "gh",
el: "gr",
en: "us",
es: "es",
et: "ee",
eu: "es-pv",
fa: "ir",
fi: "fi",
fil: "ph",
fj: "fj",
fo: "fo",
fr: "fr",
fy: "nl-fr",
ga: "ie",
gd: "gb-sct",
gl: "es-ga",
gn: "py",
gu: "in-gj",
gv: "im",
ha: "ng",
haw: "us-hi",
he: "il",
hi: "in",
hmn: "hmong",
ho: "pg",
hr: "hr",
ht: "ht",
hu: "hu",
hy: "am",
id: "id",
ig: "ng",
ilo: "ph",
is: "is",
it: "it",
ja: "jp",
jv: "id-jt",
ka: "ge",
kg: "cd",
ki: "ke",
kk: "kz",
kl: "gl",
km: "kh",
kn: "in-ka",
ko: "kr",
kr: "ng",
kri: "sl",
ks: "in",
ku: "iq-kr",
kv: "ru-ko",
kw: "gb-con",
ky: "kg",
lb: "lu",
lg: "ug",
ln: "cd",
lo: "la",
lt: "lt",
lu: "cd",
lus: "in-mz",
lv: "lv",
mg: "mg",
mh: "mh",
mi: "maori",
mk: "mk",
ml: "malayali",
mn: "mn",
mni: "in-mn",
mrj: "ru",
ms: "my",
mt: "mt",
my: "mm",
na: "nr",
nb: "no",
nd: "zw",
ne: "np",
nl: "nl",
nn: "no",
no: "no",
nr: "za",
ny: "mw",
oc: "occitania",
om: "et",
or: "in-or",
os: "ru",
oto: "mx",
pa: "in",
pap: "cw",
pl: "pl",
pms: "it-21",
ps: "af",
"pt-br": "br",
pt: "pt",
qu: "pe",
rm: "ch-gr",
rn: "bi",
ro: "ro",
ru: "ru",
rw: "rw",
sc: "it-82",
sd: "pk-sd",
se: "no",
sg: "cf",
si: "lk",
sk: "sk",
sl: "si",
sm: "ws",
sn: "zw",
so: "so",
sq: "al",
sr: "rs",
ss: "sz",
st: "ls",
su: "id-jb",
sv: "se",
sw: "tz",
ta: "in-tn",
te: "in-tg",
tg: "tj",
th: "th",
ti: "er",
tk: "tm",
tl: "ph",
tn: "bw",
to: "to",
tr: "tr",
tt: "ru-ta",
ty: "pf",
udm: "ru-ud",
ug: "cn-xj",
uk: "ua",
ur: "pk",
uz: "uz",
vi: "vn",
xh: "za",
yo: "yorubaland",
yua: "mx",
zh: "cn",
zu: "za"
};
var _tmpl$ = /* @__PURE__ */ template(`<svg xmlns=http://www.w3.org/2000/svg viewBox="0 0 512 512"aria-label=Loading role=img><mask id=circular-graphic-fallback-mask><circle cx=256 cy=256 r=256 fill=#fff></circle></mask><g mask=url(#circular-graphic-fallback-mask)><path fill=#eee d="M0 0h512v512H0z"></path><circle cx=253 cy=380 r=32 fill=#acabb1></circle><path fill=#acabb1 d="M322.4 135.5c-15.6-13.6-37.4-20.3-65.5-20.3-27.9 0-49.9 7.2-66 21.4a74.9 74.9 0 0 0-24.3 55.4h-.2v12.8H224l.1-9a35.2 35.2 0 0 1 9.3-24.8c5.8-6.1 13.7-9 23.5-9 20.7 0 31 11 31 33.4 0 7.4-2 14.5-6 21.1a124.2 124.2 0 0 1-23.9 26 90.4 90.4 0 0 0-24.8 32.3c-4.5 11-6.8 26.7-6.8 45.2h51l.8-13.1a54 54 0 0 1 17.3-33.9l16.2-15.2a131.4 131.4 0 0 0 26.4-33.2 69.5 69.5 0 0 0 7.6-31.8c-.1-24.7-7.8-43.7-23.3-57.3z">`);
function FallbackSvg(props) {
return (() => {
var _el$ = _tmpl$(), _el$2 = _el$.firstChild; _el$2.nextSibling;
effect((_p$) => {
var _v$ = props.width, _v$2 = props.height;
_v$ !== _p$.e && setAttribute(_el$, "width", _p$.e = _v$);
_v$2 !== _p$.t && setAttribute(_el$, "height", _p$.t = _v$2);
return _p$;
}, {
e: void 0,
t: void 0
});
return _el$;
})();
}
var _tmpl$2 = /* @__PURE__ */ template(`<img>`);
var DEFAULT_CDN_URLS = {
country: "https://circle-flags.zeljko.me/flags/",
language: "https://circle-flags.zeljko.me/flags/language/"
};
var ENV_CDN_URL = import.meta.env.VITE_PUBLIC_CIRCLE_FLAGS_CDN_URL?.trim() || "";
function CircularGraphic(props) {
const {
code,
type,
cdn,
label,
width,
height,
alt,
src,
onError,
...restProps
} = props;
const [imgError, setImgError] = createSignal(false);
const getCdnUrl = () => {
const rawCdn = props.cdn?.trim() || ENV_CDN_URL || DEFAULT_CDN_URLS[props.type];
return rawCdn.replace(/\/+$/, "") + "/";
};
const getCleanCode = () => {
return props.code.replace(/^\/+/, "");
};
const getSourceUrl = () => {
return `${getCdnUrl()}${getCleanCode()}.svg`;
};
const getAriaLabel = () => {
return props.label || `${props.type} ${getCleanCode()} flag`;
};
const handleError = () => {
setImgError(true);
};
return memo(() => memo(() => !!!imgError())() ? (() => {
var _el$ = _tmpl$2();
_el$.addEventListener("error", handleError);
spread(_el$, mergeProps({
get src() {
return getSourceUrl();
},
get width() {
return props.width;
},
get height() {
return props.height;
},
get alt() {
return getAriaLabel();
}
}, restProps), false, false);
return _el$;
})() : createComponent(FallbackSvg, {
get width() {
return props.width;
},
get height() {
return props.height;
}
}));
}
// src/index.tsx
function CircleFlag(props) {
const {
countryCode,
width,
height,
cdn,
label,
...imgProps
} = props;
const mappedCountryCode = countryToCountryMap[countryCode];
if (mappedCountryCode !== void 0) {
return createComponent(CircularGraphic, mergeProps({
code: mappedCountryCode,
type: "country",
width,
height,
cdn,
label
}, imgProps));
} else {
return createComponent(CircularGraphic, mergeProps({
code: countryCode,
type: "country",
width,
height,
cdn,
label
}, imgProps));
}
}
function CircleFlagLanguage(props) {
const {
languageCode,
width,
height,
cdn,
label,
...imgProps
} = props;
const mappedCountryCode = languageToCountryMap[languageCode];
if (mappedCountryCode !== void 0) {
return createComponent(CircleFlag, mergeProps({
countryCode: mappedCountryCode,
width,
height,
cdn,
label
}, imgProps));
} else {
return createComponent(CircularGraphic, mergeProps({
code: languageCode,
type: "language",
width,
height,
cdn,
label
}, imgProps));
}
}
export { CircleFlag, CircleFlagLanguage };