@nonfx/vue-flagpack 2.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Yummygum
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # Flagpack
2
+
3
+ Flagpack contains 260+ flag icons to easily use within your code project. Flagpack is an open source project and available for JavaScript frameworks/libraries Angular, Vue and React.
4
+
5
+ ![Flagpack. 260+ easily implementable flag icons to use in your design or code project. Open Source. Available for Sketch, Figma, Angular, Vue, and React. [www.flagpack.xyz](https://www.flagpack.xyz). Made with love by Yummygum. Graphic showing a list with the flags of Argentina, Croatia, Estonia, Kenia, Netherlands, and Scotland.](https://flagpack.xyz/meta-image.png)
6
+
7
+ [View documentation on flagpack.xyz](https://flagpack.xyz/docs/)
8
+
9
+ ## vue-flagpack
10
+ <p>
11
+ <a href="https://www.npmjs.com/package/vue-flagpack" target="_blank">
12
+ <img src="https://img.shields.io/npm/v/vue-flagpack.svg?style=flat" />
13
+ </a>
14
+ <a href="https://www.npmjs.com/package/vue-flagpack" target="_blank">
15
+ <img src="https://img.shields.io/npm/dt/vue-flagpack.svg?style=flat" />
16
+ </a>
17
+ <a href="https://github.com/sponsors/Yummygum" target="_blank">
18
+ <img src="https://img.shields.io/badge/Support-♥-E94AAA" />
19
+ </a>
20
+ <a href="https://twitter.com/flagpack" target="_blank">
21
+ <img src="https://img.shields.io/twitter/follow/flagpack.svg?style=social&label=follow" />
22
+ </a>
23
+ </p>
24
+ Flagpack for Vue is now fully compatible with Vue 3 and Nuxt 3! The package has been updated to use Vue 3's Composition API and includes a dedicated Nuxt module for seamless integration.
25
+
26
+ ### Tree-Shaking Support
27
+
28
+ Starting from flagpack-core v2.0.0, vue-flagpack supports **tree-shaking**! This means only the flag SVGs you actually use will be included in your bundle. The Flag component uses dynamic imports to load flag SVGs on-demand, ensuring your bundle stays small and efficient.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ npm install vue-flagpack
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Vue 3
39
+
40
+ #### As a plugin
41
+ ```js
42
+ import { createApp } from 'vue'
43
+ import VueFlagpack from 'vue-flagpack'
44
+
45
+ const app = createApp(App)
46
+ app.use(VueFlagpack, {
47
+ name: 'Flag' // Optional: default component name
48
+ })
49
+ ```
50
+
51
+ In your template:
52
+ ```vue
53
+ <template>
54
+ <Flag code="NL" size="l" />
55
+ </template>
56
+ ```
57
+
58
+ #### Direct component import
59
+ ```vue
60
+ <script setup>
61
+ import { Flag } from 'vue-flagpack'
62
+ </script>
63
+
64
+ <template>
65
+ <Flag code="NL" size="m" has-drop-shadow />
66
+ </template>
67
+ ```
68
+
69
+ ### Nuxt 3
70
+
71
+ Add the module to your `nuxt.config.ts`:
72
+
73
+ ```ts
74
+ export default defineNuxtConfig({
75
+ modules: [
76
+ 'vue-flagpack/nuxt'
77
+ ]
78
+ })
79
+ ```
80
+
81
+ Then use the Flag component anywhere in your Nuxt app (auto-imported):
82
+
83
+ ```vue
84
+ <template>
85
+ <Flag code="NL" size="l" />
86
+ </template>
87
+ ```
88
+
89
+ ### Advanced: Direct Flag Import for Static Bundling
90
+
91
+ For optimal tree-shaking when you know which flags you need at build time, you can use the utility functions:
92
+
93
+ ```vue
94
+ <script setup>
95
+ import { ref, onMounted } from 'vue'
96
+ import { getFlagUrl, isoToCountryCode } from 'vue-flagpack'
97
+
98
+ const flagUrl = ref('')
99
+
100
+ onMounted(async () => {
101
+ // Only the NL flag SVG will be included in your bundle
102
+ flagUrl.value = await getFlagUrl('NL', 'l')
103
+ })
104
+ </script>
105
+
106
+ <template>
107
+ <img v-if="flagUrl" :src="flagUrl" alt="Netherlands flag" />
108
+ </template>
109
+ ```
110
+
111
+ ### Via CDN
112
+ ```html
113
+ <script src="https://unpkg.com/vue@3"></script>
114
+ <script src="https://unpkg.com/vue-flagpack@latest/dist/vue-flag-rollup.iife.js"></script>
115
+ <script>
116
+ const { createApp } = Vue
117
+ const { default: VueFlagpack, Flag } = VueFlagpack
118
+
119
+ const app = createApp({
120
+ components: { Flag }
121
+ })
122
+ app.mount('#app')
123
+ </script>
124
+ ```
125
+
126
+ ## Available plugin options
127
+
128
+ | Key | Value | Required | Default |
129
+ |-------|-------|------|------|
130
+ | name | String | false | vue-flagpack |
131
+
132
+
133
+
134
+ ## How Tree-Shaking Works
135
+
136
+ Vue-flagpack leverages **dynamic imports** to ensure only the flag SVGs you use are included in your final bundle:
137
+
138
+ - **Dynamic Loading**: The `Flag` component dynamically imports SVG files at runtime based on the `code` prop
139
+ - **No Bloat**: Unlike v1, all 250+ flags are NOT bundled into your app by default
140
+ - **Optimized Bundles**: Modern bundlers (Vite, Webpack 5, Rollup) will code-split flag SVGs into separate chunks
141
+ - **On-Demand**: Flags are loaded when the component renders, keeping initial bundle size minimal
142
+
143
+ ### Bundle Size Comparison
144
+
145
+ - **Without tree-shaking (v1.x)**: ~16MB (all flags bundled)
146
+ - **With tree-shaking (v2.x)**: ~4KB base + ~1-2KB per flag used
147
+
148
+ Example: If your app only uses 5 country flags, your bundle will be ~14KB instead of 16MB!
149
+
150
+ ## Available component configurations — Props
151
+
152
+ | Key | Value | Required | Default | Format |
153
+ |-------|-------|------|------|------|
154
+ | code | String | false | 'NL' | [See all codes](https://flagpack.xyz/docs/flag-index/) |
155
+ | size | String | false | 'L' | 'S', 'M' or 'L' |
156
+ | className | String | false | - | - |
157
+ | hasDropShadow | Boolean | false | false | - |
158
+ | hasBorder | Boolean | false | true | - |
159
+ | hasBorderRadius | Boolean | false | true | - |
160
+ | gradient | String | false | '' | 'top-down', 'real-linear' or 'real-circular' |
161
+
162
+
163
+
164
+ ## Build Dist
165
+
166
+ ```bash
167
+ # install dependencies
168
+ npm install
169
+
170
+ # build for prod
171
+ npm run build
172
+
173
+ # build with watcher for dev
174
+ npm run dev
175
+ ```
176
+
177
+ ## Releasing
178
+ To release a new version you'll need to make sure all changes commits are done and pushed. After that you'll need to decide which release type you want to use. The release types are; patch (0.0.1), major (0.1.0), or minor (1.0.0).
179
+ ```
180
+ npm version <release_type>
181
+ ```
182
+ This will update the version number in the `package.json`, and will add a git tag automatically. Next you'll need to push the git tag to the remote.
183
+ ```
184
+ git push --tags origin main
185
+ ```
186
+ After that you'll need to publish to npm.
187
+ ```
188
+ npm publish
189
+ ```
190
+
191
+ When you're confident with the release, make sure the version tag is also released at GitHub.
192
+
193
+ ## Support
194
+
195
+ [Frequently Asked Questions](https://flagpack.xyz/support/)
196
+
197
+ [Documentation](https://flagpack.xyz/docs/)
198
+
199
+ ## Releases
200
+
201
+ You can find a changelog of Flagpack's releases on the [Releases page](https://github.com/Yummygum/vue-flagpack/releases) on GitHub.
202
+
203
+ ## Contribute
204
+
205
+ If you're interested in contributing to this project, great! Please see the [contributing document](CONTRIBUTING.md).
206
+
207
+ ## License
208
+
209
+ Flagpack is an open source project published under a [MIT license](LICENSE).
@@ -0,0 +1,62 @@
1
+ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
2
+ size: {
3
+ default: string;
4
+ };
5
+ code: {
6
+ default: string;
7
+ };
8
+ hasDropShadow: {
9
+ type: BooleanConstructor;
10
+ default: boolean;
11
+ };
12
+ hasBorder: {
13
+ type: BooleanConstructor;
14
+ default: boolean;
15
+ };
16
+ hasBorderRadius: {
17
+ type: BooleanConstructor;
18
+ default: boolean;
19
+ };
20
+ gradient: {
21
+ default: undefined;
22
+ };
23
+ className: {
24
+ default: string;
25
+ };
26
+ }>, (_ctx: any, _cache: any) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
27
+ [key: string]: any;
28
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
29
+ size: {
30
+ default: string;
31
+ };
32
+ code: {
33
+ default: string;
34
+ };
35
+ hasDropShadow: {
36
+ type: BooleanConstructor;
37
+ default: boolean;
38
+ };
39
+ hasBorder: {
40
+ type: BooleanConstructor;
41
+ default: boolean;
42
+ };
43
+ hasBorderRadius: {
44
+ type: BooleanConstructor;
45
+ default: boolean;
46
+ };
47
+ gradient: {
48
+ default: undefined;
49
+ };
50
+ className: {
51
+ default: string;
52
+ };
53
+ }>> & Readonly<{}>, {
54
+ size: string;
55
+ code: string;
56
+ hasDropShadow: boolean;
57
+ hasBorder: boolean;
58
+ hasBorderRadius: boolean;
59
+ gradient: undefined;
60
+ className: string;
61
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
62
+ export default _default;
package/dist/nuxt.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare const _default: NuxtModule<TOptions, TOptions, false>;
2
+ export default _default;
package/dist/nuxt.mjs ADDED
@@ -0,0 +1 @@
1
+ import{defineNuxtModule as a,addComponent as e}from"@nuxt/kit";var t=a({meta:{name:"vue-flagpack",configKey:"vueFlagpack",compatibility:{nuxt:"^3.0.0"}},defaults:{},setup(a,t){e({name:"Flag",filePath:"vue-flagpack",export:"Flag"})}});export{t as default};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Get the flag SVG URL for a given country code and size
3
+ * This uses dynamic imports to enable tree-shaking
4
+ */
5
+ export declare function getFlagUrl(code: string, size?: 's' | 'm' | 'l'): Promise<string>;
6
+ /**
7
+ * Helper to import a specific flag statically for maximum tree-shaking
8
+ * Usage: const nlFlag = await importFlag('NL', 'l')
9
+ */
10
+ export declare function importFlag(code: string, size?: 's' | 'm' | 'l'): Promise<string>;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),a=require("flagpack-core");const n=["src"];var o=e.defineComponent({__name:"Flag",props:{size:{default:"m"},code:{default:"528"},hasDropShadow:{type:Boolean,default:!1},hasBorder:{type:Boolean,default:!0},hasBorderRadius:{type:Boolean,default:!0},gradient:{default:void 0},className:{default:""}},setup(o){const r=o,t=e.ref(""),d=async()=>{try{const e=a.isoToCountryCode(r.code).toUpperCase(),n=r.size.toLowerCase(),o=await import(`flagpack-core/lib/flags/${n}/${e}.svg`);t.value=o.default}catch(e){console.warn(`Flag not found for code: ${r.code}`,e),t.value=""}};return e.onMounted(()=>{d()}),e.watch(()=>[r.code,r.size],()=>{d()}),(a,r)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["flag",`size-${o.size}`,{"border-radius":o.hasBorderRadius},{border:o.hasBorder},{"drop-shadow":o.hasDropShadow},o.gradient,o.className])},[t.value?(e.openBlock(),e.createElementBlock("img",{key:0,src:t.value,alt:"flag"},null,8,n)):e.createCommentVNode("",!0)],2))}});async function r(e,n="m"){try{const o=a.isoToCountryCode(e).toUpperCase(),r=n.toLowerCase();return(await import(`flagpack-core/lib/flags/${r}/${o}.svg`)).default}catch(a){return console.warn(`Flag not found for code: ${e}`,a),""}}!function(e,a){void 0===a&&(a={});var n=a.insertAt;if("undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css","top"===n&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e))}}('.flag[data-v-a804f4ce] {\n display: inline-block;\n overflow: hidden;\n position: relative;\n box-sizing: border-box;\n}\n.flag.size-s[data-v-a804f4ce] {\n width: 16px;\n height: 12px;\n}\n.flag.size-s.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 0 1px 0.5px rgba(0, 0, 0, 0.1);\n}\n.flag.size-s.border-radius[data-v-a804f4ce] {\n border-radius: 1px;\n}\n.flag.size-m[data-v-a804f4ce] {\n width: 20px;\n height: 15px;\n}\n.flag.size-m.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);\n}\n.flag.size-m.border-radius[data-v-a804f4ce] {\n border-radius: 1.5px;\n}\n.flag.size-l[data-v-a804f4ce] {\n width: 32px;\n height: 24px;\n}\n.flag.size-l.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.1);\n}\n.flag.size-l.border-radius[data-v-a804f4ce] {\n border-radius: 2px;\n}\n.flag.border[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n border: 1px solid rgba(0, 0, 0, 0.5);\n mix-blend-mode: overlay;\n}\n.flag.border-radius[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n border-radius: 1px;\n}\n.flag.top-down[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.3) 2%, rgba(255, 255, 255, 0.7) 100%);\n}\n.flag.real-linear[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.2) 0%, rgba(39, 39, 39, 0.22) 11%, rgba(255, 255, 255, 0.3) 27%, rgba(0, 0, 0, 0.24) 41%, rgba(0, 0, 0, 0.55) 52%, rgba(255, 255, 255, 0.26) 63%, rgba(0, 0, 0, 0.27) 74%, rgba(255, 255, 255, 0.3) 100%);\n}\n.flag.real-circular[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background: radial-gradient(50% 36%, rgba(255, 255, 255, 0.3) 0%, rgba(0, 0, 0, 0.24) 11%, rgba(0, 0, 0, 0.55) 17%, rgba(255, 255, 255, 0.26) 22%, rgba(0, 0, 0, 0.17) 27%, rgba(255, 255, 255, 0.28) 31%, rgba(255, 255, 255, 0) 37%) center calc(50% - 8px)/600% 600%, radial-gradient(50% 123%, rgba(255, 255, 255, 0.3) 25%, rgba(0, 0, 0, 0.24) 48%, rgba(0, 0, 0, 0.55) 61%, rgba(255, 255, 255, 0.26) 72%, rgba(0, 0, 0, 0.17) 80%, rgba(255, 255, 255, 0.28) 88%, rgba(255, 255, 255, 0.3) 100%) center calc(50% - 8px)/600% 600%;\n}\n.flag img[data-v-a804f4ce] {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}'),o.__scopeId="data-v-a804f4ce";var t={install:(e,a={})=>{e.component(a.name||"Flag",o)}};Object.defineProperty(exports,"isoToCountryCode",{enumerable:!0,get:function(){return a.isoToCountryCode}}),exports.Flag=o,exports.default=t,exports.getFlagUrl=r,exports.importFlag=async function(e,a="m"){return r(e,a)};
@@ -0,0 +1 @@
1
+ import{defineComponent as a,ref as e,onMounted as n,watch as o,createElementBlock as r,openBlock as d,normalizeClass as t,createCommentVNode as i}from"vue";import{isoToCountryCode as l}from"flagpack-core";export{isoToCountryCode}from"flagpack-core";const s=["src"];var g=a({__name:"Flag",props:{size:{default:"m"},code:{default:"528"},hasDropShadow:{type:Boolean,default:!1},hasBorder:{type:Boolean,default:!0},hasBorderRadius:{type:Boolean,default:!0},gradient:{default:void 0},className:{default:""}},setup(a){const g=a,b=e(""),c=async()=>{try{const a=l(g.code).toUpperCase(),e=g.size.toLowerCase(),n=await import(`flagpack-core/lib/flags/${e}/${a}.svg`);b.value=n.default}catch(a){console.warn(`Flag not found for code: ${g.code}`,a),b.value=""}};return n(()=>{c()}),o(()=>[g.code,g.size],()=>{c()}),(e,n)=>(d(),r("div",{class:t(["flag",`size-${a.size}`,{"border-radius":a.hasBorderRadius},{border:a.hasBorder},{"drop-shadow":a.hasDropShadow},a.gradient,a.className])},[b.value?(d(),r("img",{key:0,src:b.value,alt:"flag"},null,8,s)):i("",!0)],2))}});async function b(a,e="m"){try{const n=l(a).toUpperCase(),o=e.toLowerCase();return(await import(`flagpack-core/lib/flags/${o}/${n}.svg`)).default}catch(e){return console.warn(`Flag not found for code: ${a}`,e),""}}async function c(a,e="m"){return b(a,e)}!function(a,e){void 0===e&&(e={});var n=e.insertAt;if("undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css","top"===n&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=a:r.appendChild(document.createTextNode(a))}}('.flag[data-v-a804f4ce] {\n display: inline-block;\n overflow: hidden;\n position: relative;\n box-sizing: border-box;\n}\n.flag.size-s[data-v-a804f4ce] {\n width: 16px;\n height: 12px;\n}\n.flag.size-s.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 0 1px 0.5px rgba(0, 0, 0, 0.1);\n}\n.flag.size-s.border-radius[data-v-a804f4ce] {\n border-radius: 1px;\n}\n.flag.size-m[data-v-a804f4ce] {\n width: 20px;\n height: 15px;\n}\n.flag.size-m.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);\n}\n.flag.size-m.border-radius[data-v-a804f4ce] {\n border-radius: 1.5px;\n}\n.flag.size-l[data-v-a804f4ce] {\n width: 32px;\n height: 24px;\n}\n.flag.size-l.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.1);\n}\n.flag.size-l.border-radius[data-v-a804f4ce] {\n border-radius: 2px;\n}\n.flag.border[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n border: 1px solid rgba(0, 0, 0, 0.5);\n mix-blend-mode: overlay;\n}\n.flag.border-radius[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n border-radius: 1px;\n}\n.flag.top-down[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.3) 2%, rgba(255, 255, 255, 0.7) 100%);\n}\n.flag.real-linear[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.2) 0%, rgba(39, 39, 39, 0.22) 11%, rgba(255, 255, 255, 0.3) 27%, rgba(0, 0, 0, 0.24) 41%, rgba(0, 0, 0, 0.55) 52%, rgba(255, 255, 255, 0.26) 63%, rgba(0, 0, 0, 0.27) 74%, rgba(255, 255, 255, 0.3) 100%);\n}\n.flag.real-circular[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background: radial-gradient(50% 36%, rgba(255, 255, 255, 0.3) 0%, rgba(0, 0, 0, 0.24) 11%, rgba(0, 0, 0, 0.55) 17%, rgba(255, 255, 255, 0.26) 22%, rgba(0, 0, 0, 0.17) 27%, rgba(255, 255, 255, 0.28) 31%, rgba(255, 255, 255, 0) 37%) center calc(50% - 8px)/600% 600%, radial-gradient(50% 123%, rgba(255, 255, 255, 0.3) 25%, rgba(0, 0, 0, 0.24) 48%, rgba(0, 0, 0, 0.55) 61%, rgba(255, 255, 255, 0.26) 72%, rgba(0, 0, 0, 0.17) 80%, rgba(255, 255, 255, 0.28) 88%, rgba(255, 255, 255, 0.3) 100%) center calc(50% - 8px)/600% 600%;\n}\n.flag img[data-v-a804f4ce] {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}'),g.__scopeId="data-v-a804f4ce";var f={install:(a,e={})=>{a.component(e.name||"Flag",g)}};export{g as Flag,f as default,b as getFlagUrl,c as importFlag};
@@ -0,0 +1 @@
1
+ var VueFlagpack=function(e,a,n){"use strict";const o=["src"];var r=a.defineComponent({__name:"Flag",props:{size:{default:"m"},code:{default:"528"},hasDropShadow:{type:Boolean,default:!1},hasBorder:{type:Boolean,default:!0},hasBorderRadius:{type:Boolean,default:!0},gradient:{default:void 0},className:{default:""}},setup(e){const r=e,t=a.ref(""),d=async()=>{try{const e=n.isoToCountryCode(r.code).toUpperCase(),a=r.size.toLowerCase(),o=await import(`flagpack-core/lib/flags/${a}/${e}.svg`);t.value=o.default}catch(e){console.warn(`Flag not found for code: ${r.code}`,e),t.value=""}};return a.onMounted(()=>{d()}),a.watch(()=>[r.code,r.size],()=>{d()}),(n,r)=>(a.openBlock(),a.createElementBlock("div",{class:a.normalizeClass(["flag",`size-${e.size}`,{"border-radius":e.hasBorderRadius},{border:e.hasBorder},{"drop-shadow":e.hasDropShadow},e.gradient,e.className])},[t.value?(a.openBlock(),a.createElementBlock("img",{key:0,src:t.value,alt:"flag"},null,8,o)):a.createCommentVNode("",!0)],2))}});async function t(e,a="m"){try{const o=n.isoToCountryCode(e).toUpperCase(),r=a.toLowerCase();return(await import(`flagpack-core/lib/flags/${r}/${o}.svg`)).default}catch(a){return console.warn(`Flag not found for code: ${e}`,a),""}}!function(e,a){void 0===a&&(a={});var n=a.insertAt;if("undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css","top"===n&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e))}}('.flag[data-v-a804f4ce] {\n display: inline-block;\n overflow: hidden;\n position: relative;\n box-sizing: border-box;\n}\n.flag.size-s[data-v-a804f4ce] {\n width: 16px;\n height: 12px;\n}\n.flag.size-s.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 0 1px 0.5px rgba(0, 0, 0, 0.1);\n}\n.flag.size-s.border-radius[data-v-a804f4ce] {\n border-radius: 1px;\n}\n.flag.size-m[data-v-a804f4ce] {\n width: 20px;\n height: 15px;\n}\n.flag.size-m.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);\n}\n.flag.size-m.border-radius[data-v-a804f4ce] {\n border-radius: 1.5px;\n}\n.flag.size-l[data-v-a804f4ce] {\n width: 32px;\n height: 24px;\n}\n.flag.size-l.drop-shadow[data-v-a804f4ce] {\n box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.1);\n}\n.flag.size-l.border-radius[data-v-a804f4ce] {\n border-radius: 2px;\n}\n.flag.border[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n border: 1px solid rgba(0, 0, 0, 0.5);\n mix-blend-mode: overlay;\n}\n.flag.border-radius[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n border-radius: 1px;\n}\n.flag.top-down[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.3) 2%, rgba(255, 255, 255, 0.7) 100%);\n}\n.flag.real-linear[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.2) 0%, rgba(39, 39, 39, 0.22) 11%, rgba(255, 255, 255, 0.3) 27%, rgba(0, 0, 0, 0.24) 41%, rgba(0, 0, 0, 0.55) 52%, rgba(255, 255, 255, 0.26) 63%, rgba(0, 0, 0, 0.27) 74%, rgba(255, 255, 255, 0.3) 100%);\n}\n.flag.real-circular[data-v-a804f4ce]::before {\n content: "";\n width: 100%;\n height: 100%;\n position: absolute;\n display: block;\n mix-blend-mode: overlay;\n box-sizing: border-box;\n background: radial-gradient(50% 36%, rgba(255, 255, 255, 0.3) 0%, rgba(0, 0, 0, 0.24) 11%, rgba(0, 0, 0, 0.55) 17%, rgba(255, 255, 255, 0.26) 22%, rgba(0, 0, 0, 0.17) 27%, rgba(255, 255, 255, 0.28) 31%, rgba(255, 255, 255, 0) 37%) center calc(50% - 8px)/600% 600%, radial-gradient(50% 123%, rgba(255, 255, 255, 0.3) 25%, rgba(0, 0, 0, 0.24) 48%, rgba(0, 0, 0, 0.55) 61%, rgba(255, 255, 255, 0.26) 72%, rgba(0, 0, 0, 0.17) 80%, rgba(255, 255, 255, 0.28) 88%, rgba(255, 255, 255, 0.3) 100%) center calc(50% - 8px)/600% 600%;\n}\n.flag img[data-v-a804f4ce] {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}'),r.__scopeId="data-v-a804f4ce";var d={install:(e,a={})=>{e.component(a.name||"Flag",r)}};return Object.defineProperty(e,"isoToCountryCode",{enumerable:!0,get:function(){return n.isoToCountryCode}}),e.Flag=r,e.default=d,e.getFlagUrl=t,e.importFlag=async function(e,a="m"){return t(e,a)},Object.defineProperty(e,"__esModule",{value:!0}),e}({},Vue,flagpackCore);
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@nonfx/vue-flagpack",
3
+ "description": "Gorgeous flag components for your Vue 3 and Nuxt 3 project with tree-shaking support.",
4
+ "version": "2.0.0",
5
+ "type": "module",
6
+ "author": "Yummygum <info@yummygum.com> (https://yummygum.com)",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Yummygum/vue-flagpack.git"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "keywords": [
15
+ "vue",
16
+ "vue-component",
17
+ "languages",
18
+ "flag",
19
+ "iso",
20
+ "flag set",
21
+ "countries"
22
+ ],
23
+ "files": [
24
+ "dist/*",
25
+ "src/*"
26
+ ],
27
+ "main": "./dist/vue-flag-rollup.cjs.js",
28
+ "module": "./dist/vue-flag-rollup.esm.js",
29
+ "types": "./src/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "import": "./dist/vue-flag-rollup.esm.js",
33
+ "require": "./dist/vue-flag-rollup.cjs.js"
34
+ },
35
+ "./nuxt": {
36
+ "import": "./dist/nuxt.mjs"
37
+ }
38
+ },
39
+ "license": "MIT",
40
+ "bugs": {
41
+ "url": "https://github.com/Yummygum/vue-flagpack/issues"
42
+ },
43
+ "homepage": "https://flagpack.xyz",
44
+ "scripts": {
45
+ "dev": "NODE_ENV=development rollup -cw",
46
+ "prebuild": "rm -rf dist",
47
+ "build": "NODE_ENV=production rollup -c"
48
+ },
49
+ "browserslist": [
50
+ "> 1%",
51
+ "last 2 versions",
52
+ "not ie <= 8"
53
+ ],
54
+ "devDependencies": {
55
+ "@nuxt/kit": "^3.10.0",
56
+ "@rollup/plugin-commonjs": "^25.0.0",
57
+ "@rollup/plugin-node-resolve": "^15.0.0",
58
+ "@rollup/plugin-terser": "^0.4.4",
59
+ "@vitejs/plugin-vue": "^5.0.0",
60
+ "@vue/compiler-sfc": "^3.4.0",
61
+ "postcss": "^8.4.0",
62
+ "rollup": "^4.0.0",
63
+ "rollup-plugin-postcss": "^4.0.2",
64
+ "rollup-plugin-typescript2": "^0.36.0",
65
+ "rollup-plugin-vue": "^6.0.0",
66
+ "sass": "^1.70.0",
67
+ "typescript": "^5.3.0",
68
+ "vue": "^3.4.0"
69
+ },
70
+ "authors": [
71
+ {
72
+ "name": "Noud Adrichem",
73
+ "social": "@noudadrichem",
74
+ "url": "https://noudadrichem.com"
75
+ },
76
+ {
77
+ "name": "Donovan Roubos",
78
+ "social": "@donovanroubos",
79
+ "url": "https://donovanroubos.nl"
80
+ },
81
+ {
82
+ "name": "Yummygum",
83
+ "social": "@yummygum",
84
+ "url": "https://yummygum.com"
85
+ }
86
+ ],
87
+ "dependencies": {
88
+ "flagpack-core": "^2.1.0"
89
+ },
90
+ "peerDependencies": {
91
+ "vue": "^3.0.0"
92
+ }
93
+ }
package/src/Flag.vue ADDED
@@ -0,0 +1,173 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ 'flag',
5
+ `size-${size}`,
6
+ {'border-radius': hasBorderRadius },
7
+ {'border': hasBorder },
8
+ {'drop-shadow': hasDropShadow},
9
+ gradient,
10
+ className
11
+ ]">
12
+ <img v-if="flagSvg" :src="flagSvg" alt="flag">
13
+ </div>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import { ref, watch, onMounted } from 'vue'
18
+ import { isoToCountryCode } from 'flagpack-core'
19
+
20
+ interface Props {
21
+ size?: 's' | 'm' | 'l'
22
+ code?: string
23
+ hasDropShadow?: boolean
24
+ hasBorder?: boolean
25
+ hasBorderRadius?: boolean
26
+ gradient?: 'top-down' | 'real-linear' | 'real-circular'
27
+ className?: string
28
+ }
29
+
30
+ const props = withDefaults(defineProps<Props>(), {
31
+ size: 'm',
32
+ code: '528',
33
+ hasDropShadow: false,
34
+ hasBorder: true,
35
+ hasBorderRadius: true,
36
+ gradient: undefined,
37
+ className: ''
38
+ })
39
+
40
+ const flagSvg = ref<string>('')
41
+
42
+ const loadFlag = async () => {
43
+ try {
44
+ const countryCode = isoToCountryCode(props.code).toUpperCase()
45
+ const sizeKey = props.size.toLowerCase()
46
+
47
+ // Dynamically import the SVG for tree-shaking
48
+ // This ensures only the flags you use are bundled
49
+ const svgModule = await import(
50
+ /* @vite-ignore */
51
+ `flagpack-core/lib/flags/${sizeKey}/${countryCode}.svg`
52
+ )
53
+
54
+ flagSvg.value = svgModule.default
55
+ } catch (error) {
56
+ console.warn(`Flag not found for code: ${props.code}`, error)
57
+ flagSvg.value = ''
58
+ }
59
+ }
60
+
61
+ // Load flag on mount and when code/size changes
62
+ onMounted(() => {
63
+ loadFlag()
64
+ })
65
+
66
+ watch(() => [props.code, props.size], () => {
67
+ loadFlag()
68
+ })
69
+ </script>
70
+
71
+ <style scoped lang="scss">
72
+ @mixin before-styling {
73
+ content: '';
74
+ width: 100%;
75
+ height: 100%;
76
+ position: absolute;
77
+ display: block;
78
+ mix-blend-mode: overlay;
79
+ box-sizing: border-box;
80
+ }
81
+
82
+ .flag {
83
+ display: inline-block;
84
+ overflow: hidden;
85
+ position: relative;
86
+ box-sizing: border-box;
87
+
88
+ &.size {
89
+ &-s {
90
+ width: 16px;
91
+ height: 12px;
92
+
93
+ &.drop-shadow {
94
+ box-shadow: 0 0 1px 0.5px rgba(0,0,0,0.10);
95
+ }
96
+
97
+ &.border-radius {
98
+ border-radius: 1px;
99
+ }
100
+ }
101
+
102
+ &-m {
103
+ width: 20px;
104
+ height: 15px;
105
+
106
+ &.drop-shadow {
107
+ box-shadow: 0 1px 2px 0 rgba(0,0,0,0.10);
108
+ }
109
+
110
+ &.border-radius {
111
+ border-radius: 1.5px;
112
+ }
113
+ }
114
+
115
+ &-l {
116
+ width: 32px;
117
+ height: 24px;
118
+
119
+ &.drop-shadow {
120
+ box-shadow: 0 2px 3px 0 rgba(0,0,0,0.10);
121
+ }
122
+
123
+ &.border-radius {
124
+ border-radius: 2px;
125
+ }
126
+ }
127
+ }
128
+
129
+ &.border {
130
+ &::before {
131
+ @include before-styling();
132
+ border: 1px solid rgba(0, 0, 0, .5);
133
+ mix-blend-mode: overlay;
134
+ }
135
+ }
136
+
137
+ &.border-radius {
138
+ &::before {
139
+ @include before-styling();
140
+ border-radius: 1px;
141
+ }
142
+ }
143
+
144
+ &.top-down {
145
+ &::before {
146
+ @include before-styling();
147
+ background-image: linear-gradient(0deg, rgba(0,0,0,0.30) 2%, rgba(255,255,255,0.70) 100%);
148
+ }
149
+ }
150
+
151
+ &.real-linear {
152
+ &::before {
153
+ @include before-styling();
154
+ background-image: linear-gradient(45deg, rgba(0,0,0,0.20) 0%, rgba(39,39,39,0.22) 11%, rgba(255,255,255,0.30) 27%, rgba(0,0,0,0.24) 41%, rgba(0,0,0,0.55) 52%, rgba(255,255,255,0.26) 63%, rgba(0,0,0,0.27) 74%, rgba(255,255,255,0.30) 100%);
155
+ }
156
+ }
157
+
158
+ &.real-circular {
159
+ &::before {
160
+ @include before-styling();
161
+ background: radial-gradient(50% 36%, rgba(255,255,255,0.30) 0%, rgba(0,0,0,0.24) 11%, rgba(0,0,0,0.55) 17%, rgba(255,255,255,0.26) 22%, rgba(0,0,0,0.17) 27%, rgba(255,255,255,0.28) 31%, rgba(255,255,255,0.00) 37%) center calc(50% - 8px) / 600% 600%,
162
+ radial-gradient(50% 123%, rgba(255,255,255,0.30) 25%, rgba(0,0,0,0.24) 48%, rgba(0,0,0,0.55) 61%, rgba(255,255,255,0.26) 72%, rgba(0,0,0,0.17) 80%, rgba(255,255,255,0.28) 88%, rgba(255,255,255,0.30) 100%) center calc(50% - 8px) / 600% 600%;
163
+ }
164
+ }
165
+
166
+ img {
167
+ display: block;
168
+ width: 100%;
169
+ height: 100%;
170
+ object-fit: cover;
171
+ }
172
+ }
173
+ </style>
package/src/index.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { App, Plugin } from 'vue'
2
+ import { DefineComponent } from 'vue'
3
+
4
+ export interface FlagProps {
5
+ size?: 's' | 'm' | 'l'
6
+ code?: string
7
+ hasDropShadow?: boolean
8
+ hasBorder?: boolean
9
+ hasBorderRadius?: boolean
10
+ gradient?: 'top-down' | 'real-linear' | 'real-circular'
11
+ className?: string
12
+ }
13
+
14
+ export const Flag: DefineComponent<FlagProps>
15
+
16
+ export interface PluginOptions {
17
+ name?: string
18
+ }
19
+
20
+ /**
21
+ * Get the flag SVG URL for a given country code and size
22
+ * This uses dynamic imports to enable tree-shaking
23
+ */
24
+ export function getFlagUrl(
25
+ code: string,
26
+ size?: 's' | 'm' | 'l'
27
+ ): Promise<string>
28
+
29
+ /**
30
+ * Helper to import a specific flag statically for maximum tree-shaking
31
+ */
32
+ export function importFlag(
33
+ code: string,
34
+ size?: 's' | 'm' | 'l'
35
+ ): Promise<string>
36
+
37
+ /**
38
+ * Convert ISO code to country code
39
+ */
40
+ export function isoToCountryCode(code: string): string
41
+
42
+ declare const plugin: Plugin & {
43
+ install: (app: App, options?: PluginOptions) => void
44
+ }
45
+
46
+ export default plugin
package/src/main.js ADDED
@@ -0,0 +1,11 @@
1
+ import Flag from './Flag.vue'
2
+ export { isoToCountryCode } from 'flagpack-core'
3
+ export { getFlagUrl, importFlag } from './utils'
4
+
5
+ export { Flag }
6
+
7
+ export default {
8
+ install: (app, options = {}) => {
9
+ app.component(options.name || 'Flag', Flag)
10
+ }
11
+ }
package/src/nuxt.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { defineNuxtModule, addComponent } from '@nuxt/kit'
2
+
3
+ export default defineNuxtModule({
4
+ meta: {
5
+ name: 'vue-flagpack',
6
+ configKey: 'vueFlagpack',
7
+ compatibility: {
8
+ nuxt: '^3.0.0'
9
+ }
10
+ },
11
+ defaults: {},
12
+ setup(_options, _nuxt) {
13
+ // Auto-import the Flag component
14
+ addComponent({
15
+ name: 'Flag',
16
+ filePath: 'vue-flagpack',
17
+ export: 'Flag'
18
+ })
19
+ }
20
+ })
package/src/utils.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { isoToCountryCode } from 'flagpack-core'
2
+
3
+ /**
4
+ * Get the flag SVG URL for a given country code and size
5
+ * This uses dynamic imports to enable tree-shaking
6
+ */
7
+ export async function getFlagUrl(
8
+ code: string,
9
+ size: 's' | 'm' | 'l' = 'm'
10
+ ): Promise<string> {
11
+ try {
12
+ const countryCode = isoToCountryCode(code).toUpperCase()
13
+ const sizeKey = size.toLowerCase()
14
+
15
+ const svgModule = await import(
16
+ /* @vite-ignore */
17
+ `flagpack-core/lib/flags/${sizeKey}/${countryCode}.svg`
18
+ )
19
+
20
+ return svgModule.default
21
+ } catch (error) {
22
+ console.warn(`Flag not found for code: ${code}`, error)
23
+ return ''
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Helper to import a specific flag statically for maximum tree-shaking
29
+ * Usage: const nlFlag = await importFlag('NL', 'l')
30
+ */
31
+ export async function importFlag(
32
+ code: string,
33
+ size: 's' | 'm' | 'l' = 'm'
34
+ ): Promise<string> {
35
+ return getFlagUrl(code, size)
36
+ }