├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .prettierrc.js ├── LICENSE ├── README.md ├── dist └── index.js ├── jest.config.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── src ├── components │ ├── StripeElement.vue │ └── StripeElements.vue ├── index.js └── stripeElements.js ├── tests └── unit │ └── stripeElements.spec.js ├── vue-stripe-elements.code-workspace └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", { 5 | "useBuiltIns": "usage", 6 | "corejs": 3 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | }, 7 | parserOptions: { 8 | parser: '@babel/eslint-parser', 9 | }, 10 | extends: [ 11 | 'plugin:vue/recommended', 12 | 'plugin:prettier/recommended', 13 | 'prettier', 14 | ], 15 | // required to lint *.vue files 16 | plugins: ['vue'], 17 | rules: { 18 | semi: [2, 'never'], 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ["https://paypal.me/softbeehive"] 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Vue Stripe Elements CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'feat/**' 7 | - 'fix/**' 8 | - 'refactor/**' 9 | - 'master' 10 | pull_request: 11 | branches: 12 | - master 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | node-version: [16.x] 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | 25 | - name: Use Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v2 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | 30 | - name: Cache NPM 31 | uses: actions/cache@v2 32 | with: 33 | path: ~/.npm 34 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 35 | restore-keys: | 36 | ${{ runner.os }}-node- 37 | 38 | - name: Install dependencies 39 | run: npm i 40 | 41 | - name: Lint 42 | run: npm run lint 43 | 44 | - name: Unit Tests 45 | run: npm run test 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .idea 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | singleQuote: true, 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Oleksandr Bystrikov 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ Deprecated ⚠️ 2 | This package is no longer maintained. Vue 2 [reached its end-of-life](https://blog.vuejs.org/posts/vue-2-eol) on December 31st, 2023. 3 | 4 | # Vue Stripe Elements 5 | - Vue 2: deprecated ❗️ 6 | - Vue 3: use [vue-stripe-js](https://github.com/ectoflow/vue-stripe-js) ✅ 7 | 8 | # Quickstart 9 | 10 | ### 1. Install package: 11 | 12 | ```bash 13 | # npm 14 | npm i vue-stripe-elements-plus --save-dev 15 | 16 | # yarn 17 | yarn add vue-stripe-elements-plus --dev 18 | ``` 19 | 20 | ### 2. Add Stripe.js library to the page: 21 | ``` 22 | 23 | ``` 24 | > Alternatively, you can load Stripe library dynamically. Just make sure it's ready before your components mount. 25 | 26 | ### 3. Use built-in components 27 | Create card 28 | 29 | ```html 30 | 49 | 50 | 97 | ``` 98 | 99 | ### 4. Get advanced 100 | Create multiple elements 101 | 102 | ```html 103 | 109 | 114 | 119 | 120 | ``` 121 | 122 | ### 5. Go wild 123 | You can even create multiple groups, don't ask me why. It's possible. 124 | 125 | ```html 126 | 132 | 136 | 137 | 143 | 148 | 149 | ``` 150 | 151 | # Styles 152 | No base style included. Main reason: overriding it isn't fun. Style as you wish via element options: [see details](https://stripe.com/docs/js/appendix/style). 153 | 154 | # API Reference 155 | 156 | ## StripeElements.vue 157 | Think of it as of individual group of elements. It creates stripe instance and elements object. 158 | 159 | ```js 160 | import { StripeElements } from 'vue-stripe-elements-plus' 161 | ``` 162 | 163 | ### props 164 | ```js 165 | // https://stripe.com/docs/js/initializing#init_stripe_js-options 166 | stripeKey: { 167 | type: String, 168 | required: true, 169 | }, 170 | // https://stripe.com/docs/js/elements_object/create#stripe_elements-options 171 | instanceOptions: { 172 | type: Object, 173 | default: () => ({}), 174 | }, 175 | // https://stripe.com/docs/stripe.js#element-options 176 | elementsOptions: { 177 | type: Object, 178 | default: () => ({}), 179 | }, 180 | ``` 181 | 182 | ### data 183 | You can access `instance` and `elements` by adding ref to StripeElements component. 184 | ```js 185 | // data of StripeElements.vue 186 | instance: {}, 187 | elements: {}, 188 | ``` 189 | 190 | ### default scoped slot 191 | Elegant solution for props. Really handy because you can make `instance` and `elements` available to all children without adding extra code. 192 | 193 | ```html 194 | 195 | 196 | 197 | 198 | 199 | ``` 200 | 201 | ## StripeElement.vue 202 | Universal and type agnostic component. Create any element supported by Stripe. 203 | 204 | ### props 205 | ```js 206 | // elements object 207 | // https://stripe.com/docs/js/elements_object/create 208 | elements: { 209 | type: Object, 210 | required: true, 211 | }, 212 | // type of the element 213 | // https://stripe.com/docs/js/elements_object/create_element?type=card 214 | type: { 215 | type: String, 216 | default: () => 'card', 217 | }, 218 | // element options 219 | // https://stripe.com/docs/js/elements_object/create_element?type=card#elements_create-options 220 | options: { 221 | type: [Object, undefined], 222 | }, 223 | ``` 224 | 225 | ### data 226 | ```js 227 | stripeElement 228 | domElement 229 | ``` 230 | 231 | ### options 232 | Element options are reactive. Recommendation: don't use v-model on `StripeElement`, instead pass value via options. 233 | 234 | ```js 235 | data() { 236 | return { 237 | elementOptions: { 238 | value: { 239 | postalCode: '' 240 | } 241 | } 242 | } 243 | }, 244 | 245 | methods: { 246 | changePostalCode() { 247 | // will update stripe element automatically 248 | this.elementOptions.value.postalCode = '12345' 249 | } 250 | } 251 | ``` 252 | 253 | ### events 254 | Following events are emitted on StripeElement 255 | - change 256 | - ready 257 | - focus 258 | - blur 259 | - escape 260 | 261 | ```html 262 | 266 | ``` 267 | 268 | ## Helpers 269 | In case you like the manual gearbox. Check [stripeElements.js](src/stripeElements.js) for details. 270 | 271 | ```js 272 | import { initStripe, createElements, createElement } from 'vue-stripe-elements-plus' 273 | ``` 274 | 275 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("vue-stripe-elements",[],e):"object"==typeof exports?exports["vue-stripe-elements"]=e():t["vue-stripe-elements"]=e()}(this,(function(){return function(){var t={8257:function(t,e,n){var r=n(7583),o=n(9212),i=n(5637),u=r.TypeError;t.exports=function(t){if(o(t))return t;throw u(i(t)+" is not a function")}},2569:function(t,e,n){var r=n(7583),o=n(794),i=r.String,u=r.TypeError;t.exports=function(t){if(o(t))return t;throw u(i(t)+" is not an object")}},5766:function(t,e,n){var r=n(2977),o=n(6782),i=n(1825),u=function(t){return function(e,n,u){var c,s=r(e),f=i(s),a=o(u,f);if(t&&n!=n){for(;f>a;)if((c=s[a++])!=c)return!0}else for(;f>a;a++)if((t||a in s)&&s[a]===n)return t||a||0;return!t&&-1}};t.exports={includes:u(!0),indexOf:u(!1)}},9624:function(t,e,n){var r=n(7386),o=r({}.toString),i=r("".slice);t.exports=function(t){return i(o(t),8,-1)}},3058:function(t,e,n){var r=n(7583),o=n(8191),i=n(9212),u=n(9624),c=n(3649)("toStringTag"),s=r.Object,f="Arguments"==u(function(){return arguments}());t.exports=o?u:function(t){var e,n,r;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=s(t),c))?n:f?u(e):"Object"==(r=u(e))&&i(e.callee)?"Arguments":r}},3478:function(t,e,n){var r=n(2870),o=n(929),i=n(6683),u=n(4615);t.exports=function(t,e){for(var n=o(e),c=u.f,s=i.f,f=0;f0&&r[0]<4?1:+(r[0]+r[1])),!o&&u&&(!(r=u.match(/Edge\/(\d+)/))||r[1]>=74)&&(r=u.match(/Chrome\/(\d+)/))&&(o=+r[1]),t.exports=o},5690:function(t){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},7263:function(t,e,n){var r=n(7583),o=n(6683).f,i=n(57),u=n(1270),c=n(460),s=n(3478),f=n(4451);t.exports=function(t,e){var n,a,p,l,v,m=t.target,d=t.global,h=t.stat;if(n=d?r:h?r[m]||c(m,{}):(r[m]||{}).prototype)for(a in e){if(l=e[a],p=t.noTargetGet?(v=o(n,a))&&v.value:n[a],!f(d?a:m+(h?".":"#")+a,t.forced)&&void 0!==p){if(typeof l==typeof p)continue;s(l,p)}(t.sham||p&&p.sham)&&i(l,"sham",!0),u(n,a,l,t)}}},6544:function(t){t.exports=function(t){try{return!!t()}catch(t){return!0}}},8262:function(t){var e=Function.prototype.call;t.exports=e.bind?e.bind(e):function(){return e.apply(e,arguments)}},4340:function(t,e,n){var r=n(8494),o=n(2870),i=Function.prototype,u=r&&Object.getOwnPropertyDescriptor,c=o(i,"name"),s=c&&"something"===function(){}.name,f=c&&(!r||r&&u(i,"name").configurable);t.exports={EXISTS:c,PROPER:s,CONFIGURABLE:f}},7386:function(t){var e=Function.prototype,n=e.bind,r=e.call,o=n&&n.bind(r);t.exports=n?function(t){return t&&o(r,t)}:function(t){return t&&function(){return r.apply(t,arguments)}}},5897:function(t,e,n){var r=n(7583),o=n(9212),i=function(t){return o(t)?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t]):r[t]&&r[t][e]}},911:function(t,e,n){var r=n(8257);t.exports=function(t,e){var n=t[e];return null==n?void 0:r(n)}},7583:function(t,e,n){var r=function(t){return t&&t.Math==Math&&t};t.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},2870:function(t,e,n){var r=n(7386),o=n(1324),i=r({}.hasOwnProperty);t.exports=Object.hasOwn||function(t,e){return i(o(t),e)}},4639:function(t){t.exports={}},275:function(t,e,n){var r=n(8494),o=n(6544),i=n(6668);t.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},5044:function(t,e,n){var r=n(7583),o=n(7386),i=n(6544),u=n(9624),c=r.Object,s=o("".split);t.exports=i((function(){return!c("z").propertyIsEnumerable(0)}))?function(t){return"String"==u(t)?s(t,""):c(t)}:c},9734:function(t,e,n){var r=n(7386),o=n(9212),i=n(1314),u=r(Function.toString);o(i.inspectSource)||(i.inspectSource=function(t){return u(t)}),t.exports=i.inspectSource},2743:function(t,e,n){var r,o,i,u=n(9491),c=n(7583),s=n(7386),f=n(794),a=n(57),p=n(2870),l=n(1314),v=n(9137),m=n(4639),d="Object already initialized",h=c.TypeError,y=c.WeakMap;if(u||l.state){var b=l.state||(l.state=new y),g=s(b.get),x=s(b.has),S=s(b.set);r=function(t,e){if(x(b,t))throw new h(d);return e.facade=t,S(b,t,e),e},o=function(t){return g(b,t)||{}},i=function(t){return x(b,t)}}else{var O=v("state");m[O]=!0,r=function(t,e){if(p(t,O))throw new h(d);return e.facade=t,a(t,O,e),e},o=function(t){return p(t,O)?t[O]:{}},i=function(t){return p(t,O)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!f(e)||(n=o(e)).type!==t)throw h("Incompatible receiver, "+t+" required");return n}}}},9212:function(t){t.exports=function(t){return"function"==typeof t}},4451:function(t,e,n){var r=n(6544),o=n(9212),i=/#|\.prototype\./,u=function(t,e){var n=s[c(t)];return n==a||n!=f&&(o(e)?r(e):!!e)},c=u.normalize=function(t){return String(t).replace(i,".").toLowerCase()},s=u.data={},f=u.NATIVE="N",a=u.POLYFILL="P";t.exports=u},794:function(t,e,n){var r=n(9212);t.exports=function(t){return"object"==typeof t?null!==t:r(t)}},6268:function(t){t.exports=!1},5871:function(t,e,n){var r=n(7583),o=n(5897),i=n(9212),u=n(2447),c=n(7786),s=r.Object;t.exports=c?function(t){return"symbol"==typeof t}:function(t){var e=o("Symbol");return i(e)&&u(e.prototype,s(t))}},1825:function(t,e,n){var r=n(97);t.exports=function(t){return r(t.length)}},8640:function(t,e,n){var r=n(4061),o=n(6544);t.exports=!!Object.getOwnPropertySymbols&&!o((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&r&&r<41}))},9491:function(t,e,n){var r=n(7583),o=n(9212),i=n(9734),u=r.WeakMap;t.exports=o(u)&&/native code/.test(i(u))},4615:function(t,e,n){var r=n(7583),o=n(8494),i=n(275),u=n(2569),c=n(8734),s=r.TypeError,f=Object.defineProperty;e.f=o?f:function(t,e,n){if(u(t),e=c(e),u(n),i)try{return f(t,e,n)}catch(t){}if("get"in n||"set"in n)throw s("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},6683:function(t,e,n){var r=n(8494),o=n(8262),i=n(112),u=n(4677),c=n(2977),s=n(8734),f=n(2870),a=n(275),p=Object.getOwnPropertyDescriptor;e.f=r?p:function(t,e){if(t=c(t),e=s(e),a)try{return p(t,e)}catch(t){}if(f(t,e))return u(!o(i.f,t,e),t[e])}},9275:function(t,e,n){var r=n(8356),o=n(5690).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},4012:function(t,e){e.f=Object.getOwnPropertySymbols},2447:function(t,e,n){var r=n(7386);t.exports=r({}.isPrototypeOf)},8356:function(t,e,n){var r=n(7386),o=n(2870),i=n(2977),u=n(5766).indexOf,c=n(4639),s=r([].push);t.exports=function(t,e){var n,r=i(t),f=0,a=[];for(n in r)!o(c,n)&&o(r,n)&&s(a,n);for(;e.length>f;)o(r,n=e[f++])&&(~u(a,n)||s(a,n));return a}},5432:function(t,e,n){var r=n(8356),o=n(5690);t.exports=Object.keys||function(t){return r(t,o)}},112:function(t,e){"use strict";var n={}.propertyIsEnumerable,r=Object.getOwnPropertyDescriptor,o=r&&!n.call({1:2},1);e.f=o?function(t){var e=r(this,t);return!!e&&e.enumerable}:n},3060:function(t,e,n){"use strict";var r=n(8191),o=n(3058);t.exports=r?{}.toString:function(){return"[object "+o(this)+"]"}},6252:function(t,e,n){var r=n(7583),o=n(8262),i=n(9212),u=n(794),c=r.TypeError;t.exports=function(t,e){var n,r;if("string"===e&&i(n=t.toString)&&!u(r=o(n,t)))return r;if(i(n=t.valueOf)&&!u(r=o(n,t)))return r;if("string"!==e&&i(n=t.toString)&&!u(r=o(n,t)))return r;throw c("Can't convert object to primitive value")}},929:function(t,e,n){var r=n(5897),o=n(7386),i=n(9275),u=n(4012),c=n(2569),s=o([].concat);t.exports=r("Reflect","ownKeys")||function(t){var e=i.f(c(t)),n=u.f;return n?s(e,n(t)):e}},1270:function(t,e,n){var r=n(7583),o=n(9212),i=n(2870),u=n(57),c=n(460),s=n(9734),f=n(2743),a=n(4340).CONFIGURABLE,p=f.get,l=f.enforce,v=String(String).split("String");(t.exports=function(t,e,n,s){var f,p=!!s&&!!s.unsafe,m=!!s&&!!s.enumerable,d=!!s&&!!s.noTargetGet,h=s&&void 0!==s.name?s.name:e;o(n)&&("Symbol("===String(h).slice(0,7)&&(h="["+String(h).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),(!i(n,"name")||a&&n.name!==h)&&u(n,"name",h),(f=l(n)).source||(f.source=v.join("string"==typeof h?h:""))),t!==r?(p?!d&&t[e]&&(m=!0):delete t[e],m?t[e]=n:u(t,e,n)):m?t[e]=n:c(e,n)})(Function.prototype,"toString",(function(){return o(this)&&p(this).source||s(this)}))},3955:function(t,e,n){var r=n(7583).TypeError;t.exports=function(t){if(null==t)throw r("Can't call method on "+t);return t}},460:function(t,e,n){var r=n(7583),o=Object.defineProperty;t.exports=function(t,e){try{o(r,t,{value:e,configurable:!0,writable:!0})}catch(n){r[t]=e}return e}},9137:function(t,e,n){var r=n(7836),o=n(8284),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},1314:function(t,e,n){var r=n(7583),o=n(460),i="__core-js_shared__",u=r[i]||o(i,{});t.exports=u},7836:function(t,e,n){var r=n(6268),o=n(1314);(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.19.1",mode:r?"pure":"global",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"})},6782:function(t,e,n){var r=n(7486),o=Math.max,i=Math.min;t.exports=function(t,e){var n=r(t);return n<0?o(n+e,0):i(n,e)}},2977:function(t,e,n){var r=n(5044),o=n(3955);t.exports=function(t){return r(o(t))}},7486:function(t){var e=Math.ceil,n=Math.floor;t.exports=function(t){var r=+t;return r!=r||0===r?0:(r>0?n:e)(r)}},97:function(t,e,n){var r=n(7486),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},1324:function(t,e,n){var r=n(7583),o=n(3955),i=r.Object;t.exports=function(t){return i(o(t))}},2670:function(t,e,n){var r=n(7583),o=n(8262),i=n(794),u=n(5871),c=n(911),s=n(6252),f=n(3649),a=r.TypeError,p=f("toPrimitive");t.exports=function(t,e){if(!i(t)||u(t))return t;var n,r=c(t,p);if(r){if(void 0===e&&(e="default"),n=o(r,t,e),!i(n)||u(n))return n;throw a("Can't convert object to primitive value")}return void 0===e&&(e="number"),s(t,e)}},8734:function(t,e,n){var r=n(2670),o=n(5871);t.exports=function(t){var e=r(t,"string");return o(e)?e:e+""}},8191:function(t,e,n){var r={};r[n(3649)("toStringTag")]="z",t.exports="[object z]"===String(r)},5637:function(t,e,n){var r=n(7583).String;t.exports=function(t){try{return r(t)}catch(t){return"Object"}}},8284:function(t,e,n){var r=n(7386),o=0,i=Math.random(),u=r(1..toString);t.exports=function(t){return"Symbol("+(void 0===t?"":t)+")_"+u(++o+i,36)}},7786:function(t,e,n){var r=n(8640);t.exports=r&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},3649:function(t,e,n){var r=n(7583),o=n(7836),i=n(2870),u=n(8284),c=n(8640),s=n(7786),f=o("wks"),a=r.Symbol,p=a&&a.for,l=s?a:a&&a.withoutSetter||u;t.exports=function(t){if(!i(f,t)||!c&&"string"!=typeof f[t]){var e="Symbol."+t;c&&i(a,t)?f[t]=a[t]:f[t]=s&&p?p(e):l(e)}return f[t]}},9751:function(t,e,n){var r=n(7263),o=n(1324),i=n(5432);r({target:"Object",stat:!0,forced:n(6544)((function(){i(1)}))},{keys:function(t){return i(o(t))}})},6394:function(t,e,n){var r=n(8191),o=n(1270),i=n(3060);r||o(Object.prototype,"toString",i,{unsafe:!0})}},e={};function n(r){var o=e[r];if(void 0!==o)return o.exports;var i=e[r]={exports:{}};return t[r](i,i.exports,n),i.exports}n.d=function(t,e){for(var r in e)n.o(e,r)&&!n.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var r={};return function(){"use strict";n.r(r),n.d(r,{StripeElement:function(){return s},StripeElements:function(){return p},createElement:function(){return i},createElements:function(){return o},initStripe:function(){return e}});var t=function(){var t=this.$createElement;return(this._self._c||t)("div")};t._withStripped=!0;n(9751),n(6394);var e=function(t,e){if(void 0===window.Stripe){var n="Stripe v3 library is not loaded";return console.error(n),n}return window.Stripe(t,e)},o=function(t,e){if(void 0===t){var n="Instance object is not defined, make sure you initialized Stripe before creating elements";return console.error(n),n}return t.elements(e)},i=function(t,e,n){if(void 0===t){var r="Elements object is not defined. You can not create stripe element without it";return console.error(r),r}if(void 0===e){var o="elementType is required. You can not create stripe element without it";return console.error(o),o}return t.create(e,n)};function u(t,e,n,r,o,i,u,c){var s,f="function"==typeof t?t.options:t;if(e&&(f.render=e,f.staticRenderFns=n,f._compiled=!0),r&&(f.functional=!0),i&&(f._scopeId="data-v-"+i),u?(s=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(u)},f._ssrRegister=s):o&&(s=c?function(){o.call(this,(f.functional?this.parent:this).$root.$options.shadowRoot)}:o),s)if(f.functional){f._injectStyles=s;var a=f.render;f.render=function(t,e){return s.call(e),a(t,e)}}else{var p=f.beforeCreate;f.beforeCreate=p?[].concat(p,s):[s]}return{exports:t,options:f}}var c=u({name:"StripeElement",props:{elements:{type:Object,required:!0},type:{type:String,default:function(){return"card"}},options:{type:[Object,void 0],default:function(){}}},data:function(){return{stripeElement:void 0,domElement:document.createElement("div")}},computed:{elementsUsable:function(){return!!this.elements&&Object.keys(this.elements).length>0}},watch:{options:{handler:function(t){t&&this.stripeElement&&this.stripeElement.update(t)},deep:!0}},beforeDestroy:function(){this.stripeElement&&(this.stripeElement.unmount(),this.stripeElement.destroy())},mounted:function(){this.elementsUsable&&(this.mountElement(),this.handleEvents())},methods:{mountElement:function(){var t=this.domElement;return this.stripeElement=i(this.elements,this.type,this.options),this.stripeElement.mount(t),this.$el.appendChild(t),this.stripeElement},handleEvents:function(){var t=this;["change","ready","focus","blur","escape"].forEach((function(e){t.stripeElement.on(e,t.eventHandler.bind(t,e))}))},eventHandler:function(t,e){return this.$emit(t,e)}}},t,[],!1,null,null,null);c.options.__file="src/components/StripeElement.vue";var s=c.exports,f=function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.elementsUsable?n("div",[t._t("default",null,{instance:t.instance,elements:t.elements})],2):t._e()};f._withStripped=!0;var a=u({name:"StripeElements",props:{stripeKey:{type:String,required:!0},instanceOptions:{type:Object,default:function(){return{}}},elementsOptions:{type:Object,default:function(){return{}}}},data:function(){return{instance:{},elements:{}}},computed:{elementsUsable:function(){var t=this.elements;return!!t&&Object.keys(t).length>0}},mounted:function(){this.instance=e(this.stripeKey,this.instanceOptions),this.elements=o(this.instance,this.elementsOptions)}},f,[],!1,null,null,null);a.options.__file="src/components/StripeElements.vue";var p=a.exports}(),r}()})); -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * For a detailed explanation regarding each configuration property, visit: 3 | * https://jestjs.io/docs/en/configuration.html 4 | */ 5 | 6 | module.exports = { 7 | // All imported modules in your tests should be mocked automatically 8 | // automock: false, 9 | 10 | // Stop running tests after `n` failures 11 | // bail: 0, 12 | 13 | // The directory where Jest should store its cached dependency information 14 | // cacheDirectory: "/private/var/folders/2l/m0vcnpf518zbnyff69zhjl000000gn/T/jest_dx", 15 | 16 | // Automatically clear mock calls and instances between every test 17 | clearMocks: true, 18 | 19 | // Indicates whether the coverage information should be collected while executing the test 20 | // collectCoverage: false, 21 | 22 | // An array of glob patterns indicating a set of files for which coverage information should be collected 23 | // collectCoverageFrom: undefined, 24 | 25 | // The directory where Jest should output its coverage files 26 | coverageDirectory: 'coverage', 27 | 28 | // An array of regexp pattern strings used to skip coverage collection 29 | // coveragePathIgnorePatterns: [ 30 | // "/node_modules/" 31 | // ], 32 | 33 | // Indicates which provider should be used to instrument code for coverage 34 | // coverageProvider: "babel", 35 | 36 | // A list of reporter names that Jest uses when writing coverage reports 37 | // coverageReporters: [ 38 | // "json", 39 | // "text", 40 | // "lcov", 41 | // "clover" 42 | // ], 43 | 44 | // An object that configures minimum threshold enforcement for coverage results 45 | // coverageThreshold: undefined, 46 | 47 | // A path to a custom dependency extractor 48 | // dependencyExtractor: undefined, 49 | 50 | // Make calling deprecated APIs throw helpful error messages 51 | // errorOnDeprecated: false, 52 | 53 | // Force coverage collection from ignored files using an array of glob patterns 54 | // forceCoverageMatch: [], 55 | 56 | // A path to a module which exports an async function that is triggered once before all test suites 57 | // globalSetup: undefined, 58 | 59 | // A path to a module which exports an async function that is triggered once after all test suites 60 | // globalTeardown: undefined, 61 | 62 | // A set of global variables that need to be available in all test environments 63 | // globals: {}, 64 | 65 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 66 | // maxWorkers: "50%", 67 | 68 | // An array of directory names to be searched recursively up from the requiring module's location 69 | // moduleDirectories: [ 70 | // "node_modules" 71 | // ], 72 | 73 | // An array of file extensions your modules use 74 | // moduleFileExtensions: [ 75 | // "js", 76 | // "json", 77 | // "jsx", 78 | // "ts", 79 | // "tsx", 80 | // "node" 81 | // ], 82 | 83 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 84 | // moduleNameMapper: {}, 85 | 86 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 87 | // modulePathIgnorePatterns: [], 88 | 89 | // Activates notifications for test results 90 | // notify: false, 91 | 92 | // An enum that specifies notification mode. Requires { notify: true } 93 | // notifyMode: "failure-change", 94 | 95 | // A preset that is used as a base for Jest's configuration 96 | // preset: undefined, 97 | 98 | // Run tests from one or more projects 99 | // projects: undefined, 100 | 101 | // Use this configuration option to add custom reporters to Jest 102 | // reporters: undefined, 103 | 104 | // Automatically reset mock state between every test 105 | // resetMocks: false, 106 | 107 | // Reset the module registry before running each individual test 108 | // resetModules: false, 109 | 110 | // A path to a custom resolver 111 | // resolver: undefined, 112 | 113 | // Automatically restore mock state between every test 114 | // restoreMocks: false, 115 | 116 | // The root directory that Jest should scan for tests and modules within 117 | // rootDir: undefined, 118 | 119 | // A list of paths to directories that Jest should use to search for files in 120 | // roots: [ 121 | // "" 122 | // ], 123 | 124 | // Allows you to use a custom runner instead of Jest's default test runner 125 | // runner: "jest-runner", 126 | 127 | // The paths to modules that run some code to configure or set up the testing environment before each test 128 | // setupFiles: [], 129 | 130 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 131 | // setupFilesAfterEnv: [], 132 | 133 | // The number of seconds after which a test is considered as slow and reported as such in the results. 134 | // slowTestThreshold: 5, 135 | 136 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 137 | // snapshotSerializers: [], 138 | 139 | // The test environment that will be used for testing 140 | testEnvironment: 'jsdom', 141 | 142 | // Options that will be passed to the testEnvironment 143 | // testEnvironmentOptions: {}, 144 | 145 | // Adds a location field to test results 146 | // testLocationInResults: false, 147 | 148 | // The glob patterns Jest uses to detect test files 149 | // testMatch: [ 150 | // "**/__tests__/**/*.[jt]s?(x)", 151 | // "**/?(*.)+(spec|test).[tj]s?(x)" 152 | // ], 153 | 154 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 155 | // testPathIgnorePatterns: [ 156 | // "/node_modules/" 157 | // ], 158 | 159 | // The regexp pattern or array of patterns that Jest uses to detect test files 160 | // testRegex: [], 161 | 162 | // This option allows the use of a custom results processor 163 | // testResultsProcessor: undefined, 164 | 165 | // This option allows use of a custom test runner 166 | // testRunner: "jasmine2", 167 | 168 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 169 | // testURL: "http://localhost", 170 | 171 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 172 | // timers: "real", 173 | 174 | // A map from regular expressions to paths to transformers 175 | transform: { 176 | '.*\\.(js)$': 'babel-jest', 177 | }, 178 | 179 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 180 | // transformIgnorePatterns: [ 181 | // "/node_modules/", 182 | // "\\.pnp\\.[^\\/]+$" 183 | // ], 184 | 185 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 186 | // unmockedModulePathPatterns: undefined, 187 | 188 | // Indicates whether each individual test should be reported during the run 189 | // verbose: undefined, 190 | 191 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 192 | // watchPathIgnorePatterns: [], 193 | 194 | // Whether to use watchman for file crawling 195 | // watchman: true, 196 | } 197 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "./src/**/*" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-stripe-elements-plus", 3 | "version": "1.0.4", 4 | "description": "Stripe Elements components for Vue", 5 | "main": "./dist/index.js", 6 | "scripts": { 7 | "lint": "eslint --ext .js,.vue .", 8 | "build": "webpack", 9 | "test": "jest" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/ectoflow/vue-stripe-elements.git" 14 | }, 15 | "keywords": [ 16 | "vue", 17 | "stripe", 18 | "elements", 19 | "payment" 20 | ], 21 | "author": { 22 | "name": "Oleksandr Bystrikov", 23 | "url": "https://softbeehive.com" 24 | }, 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/ectoflow/vue-stripe-elements/issues" 28 | }, 29 | "homepage": "https://github.com/ectoflow/vue-stripe-elements#readme", 30 | "devDependencies": { 31 | "@babel/core": "^7.16.0", 32 | "@babel/eslint-parser": "^7.16.3", 33 | "@babel/preset-env": "^7.16.0", 34 | "babel-jest": "^27.3.1", 35 | "babel-loader": "^8.2.3", 36 | "core-js": "^3.19.1", 37 | "eslint": "^8.2.0", 38 | "eslint-config-prettier": "^8.3.0", 39 | "eslint-plugin-prettier": "^4.0.0", 40 | "eslint-plugin-vue": "^8.0.3", 41 | "jest": "^27.3.1", 42 | "prettier": "^2.4.1", 43 | "terser-webpack-plugin": "^5.2.5", 44 | "vue-loader": "^15.9.8", 45 | "vue-template-compiler": "^2.6.14", 46 | "webpack": "^5.64.0", 47 | "webpack-cli": "^4.9.1" 48 | }, 49 | "browserslist": [ 50 | "defaults" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /src/components/StripeElement.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 95 | -------------------------------------------------------------------------------- /src/components/StripeElements.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 52 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import StripeElement from './components/StripeElement' 2 | import StripeElements from './components/StripeElements' 3 | import { initStripe, createElements, createElement } from './stripeElements' 4 | 5 | export { 6 | StripeElements, 7 | StripeElement, 8 | initStripe, 9 | createElements, 10 | createElement, 11 | } 12 | -------------------------------------------------------------------------------- /src/stripeElements.js: -------------------------------------------------------------------------------- 1 | export const initStripe = (key, options) => { 2 | if (typeof window.Stripe === 'undefined') { 3 | const errorMsg = 'Stripe v3 library is not loaded' 4 | console.error(errorMsg) 5 | return errorMsg 6 | } 7 | 8 | const stripeInstance = window.Stripe(key, options) 9 | return stripeInstance 10 | } 11 | 12 | export const createElements = (instance, options) => { 13 | if (typeof instance === 'undefined') { 14 | const errorMsg = 15 | 'Instance object is not defined, make sure you initialized Stripe before creating elements' 16 | console.error(errorMsg) 17 | return errorMsg 18 | } 19 | 20 | const elements = instance.elements(options) 21 | return elements 22 | } 23 | 24 | export const createElement = (elements, elementType, options) => { 25 | if (typeof elements === 'undefined') { 26 | const errorMsg = 27 | 'Elements object is not defined. You can not create stripe element without it' 28 | console.error(errorMsg) 29 | return errorMsg 30 | } 31 | if (typeof elementType === 'undefined') { 32 | const errorMsg = 33 | 'elementType is required. You can not create stripe element without it' 34 | console.error(errorMsg) 35 | return errorMsg 36 | } 37 | 38 | const element = elements.create(elementType, options) 39 | return element 40 | } 41 | 42 | export function destroy(instance) { 43 | instance = undefined 44 | return instance 45 | } 46 | -------------------------------------------------------------------------------- /tests/unit/stripeElements.spec.js: -------------------------------------------------------------------------------- 1 | import { 2 | initStripe, 3 | createElements, 4 | createElement, 5 | } from '../../src/stripeElements' 6 | 7 | describe('initStripe', () => { 8 | test('no key, no options', () => { 9 | const errorMsg = 'Stripe v3 library is not loaded' 10 | const result = initStripe() 11 | expect(result).toBe(errorMsg) 12 | }) 13 | 14 | test('key, no options', () => { 15 | const key = '12345' 16 | const options = { c: 'd' } 17 | const mockFn = jest.fn() 18 | window.Stripe = mockFn 19 | const result = initStripe(key) 20 | expect(mockFn).toHaveBeenCalledTimes(1) 21 | expect(mockFn).toHaveBeenCalledWith(key, undefined) 22 | }) 23 | 24 | test('key and options', () => { 25 | const key = '12345' 26 | const options = { c: 'd' } 27 | const mockFn = jest.fn() 28 | window.Stripe = mockFn 29 | const result = initStripe(key, options) 30 | expect(mockFn).toHaveBeenCalledTimes(1) 31 | expect(mockFn).toHaveBeenCalledWith(key, options) 32 | }) 33 | }) 34 | 35 | describe('createElements', () => { 36 | test('no arguments', () => { 37 | const errorMsg = 38 | 'Instance object is not defined, make sure you initialized Stripe before creating elements' 39 | const result = createElements() 40 | expect(result).toBe(errorMsg) 41 | }) 42 | 43 | test('valid instance', () => { 44 | const mockFn = jest.fn() 45 | const instance = { elements: mockFn } 46 | const result = createElements(instance) 47 | expect(mockFn).toHaveBeenCalledTimes(1) 48 | }) 49 | 50 | test('options passed', () => { 51 | const mockFn = jest.fn() 52 | const instance = { elements: mockFn } 53 | const options = { a: 'b' } 54 | const result = createElements(instance, options) 55 | expect(mockFn).toHaveBeenCalledTimes(1) 56 | expect(mockFn).toHaveBeenCalledWith(options) 57 | }) 58 | }) 59 | 60 | describe('createElement', () => { 61 | test('no arguments', () => { 62 | const errorMsg = 63 | 'Elements object is not defined. You can not create stripe element without it' 64 | const result = createElement() 65 | expect(result).toBe(errorMsg) 66 | }) 67 | 68 | test('valid elements, no type', () => { 69 | const errorMsg = 70 | 'elementType is required. You can not create stripe element without it' 71 | const elements = {} 72 | const result = createElement(elements) 73 | expect(result).toBe(errorMsg) 74 | }) 75 | 76 | test('valid elements, valid type', () => { 77 | const mockFn = jest.fn() 78 | const elements = { create: mockFn } 79 | const type = 'card' 80 | const result = createElement(elements, type) 81 | expect(mockFn).toHaveBeenCalledTimes(1) 82 | }) 83 | 84 | test('options passed', () => { 85 | const mockFn = jest.fn() 86 | const elements = { create: mockFn } 87 | const type = 'card' 88 | const options = { b: 'c' } 89 | const result = createElement(elements, type, options) 90 | expect(mockFn).toHaveBeenCalledTimes(1) 91 | expect(mockFn).toHaveBeenCalledWith(type, options) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /vue-stripe-elements.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | // Vue 9 | "editor.defaultFormatter": "dbaeumer.vscode-eslint", 10 | "editor.formatOnSave": true, 11 | "editor.formatOnPaste": false, 12 | "editor.codeActionsOnSave": { 13 | "source.fixAll.eslint": true 14 | }, 15 | "eslint.alwaysShowStatus": true, 16 | "eslint.validate": [ 17 | "javascript", 18 | "javascriptreact", 19 | "vue" 20 | ], 21 | "vetur.validation.template": false, 22 | "vetur.format.enable": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const TerserPlugin = require('terser-webpack-plugin') 3 | const { VueLoaderPlugin } = require('vue-loader') 4 | 5 | module.exports = { 6 | entry: './src/index.js', 7 | mode: 'production', 8 | output: { 9 | path: path.resolve(__dirname, 'dist'), 10 | filename: 'index.js', 11 | globalObject: 'this', 12 | library: { 13 | name: 'vue-stripe-elements', 14 | type: 'umd', 15 | umdNamedDefine: true, 16 | }, 17 | }, 18 | resolve: { 19 | extensions: ['.js', '.vue'], 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.vue$/, 25 | loader: 'vue-loader', 26 | }, 27 | { 28 | test: /\.js$/, 29 | loader: 'babel-loader', 30 | }, 31 | ], 32 | }, 33 | optimization: { 34 | minimize: true, 35 | minimizer: [new TerserPlugin()], 36 | }, 37 | plugins: [new VueLoaderPlugin()], 38 | } 39 | --------------------------------------------------------------------------------