├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.js
├── build
└── rollup.config.js
├── demo
├── .browserslistrc
├── .env.development.android
├── .env.development.ios
├── .env.development.web
├── .env.production.android
├── .env.production.ios
├── .env.production.web
├── .eslintrc.js
├── .gitignore
├── README.md
├── app
│ ├── App.vue
│ ├── App_Resources
│ │ ├── Android
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── app.gradle
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── background.png
│ │ │ │ ├── icon.png
│ │ │ │ └── logo.png
│ │ │ ├── drawable-ldpi
│ │ │ │ ├── background.png
│ │ │ │ ├── icon.png
│ │ │ │ └── logo.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── background.png
│ │ │ │ ├── icon.png
│ │ │ │ └── logo.png
│ │ │ ├── drawable-nodpi
│ │ │ │ └── splash_screen.xml
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── background.png
│ │ │ │ ├── icon.png
│ │ │ │ └── logo.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── background.png
│ │ │ │ ├── icon.png
│ │ │ │ └── logo.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ │ ├── background.png
│ │ │ │ ├── icon.png
│ │ │ │ └── logo.png
│ │ │ ├── values-v21
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ └── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ └── iOS
│ │ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── icon-1024.png
│ │ │ │ ├── icon-29.png
│ │ │ │ ├── icon-29@2x.png
│ │ │ │ ├── icon-29@3x.png
│ │ │ │ ├── icon-40.png
│ │ │ │ ├── icon-40@2x.png
│ │ │ │ ├── icon-40@3x.png
│ │ │ │ ├── icon-60@2x.png
│ │ │ │ ├── icon-60@3x.png
│ │ │ │ ├── icon-76.png
│ │ │ │ ├── icon-76@2x.png
│ │ │ │ └── icon-83.5@2x.png
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.launchimage
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Default-1125h.png
│ │ │ │ ├── Default-568h@2x.png
│ │ │ │ ├── Default-667h@2x.png
│ │ │ │ ├── Default-736h@3x.png
│ │ │ │ ├── Default-Landscape-X.png
│ │ │ │ ├── Default-Landscape.png
│ │ │ │ ├── Default-Landscape@2x.png
│ │ │ │ ├── Default-Landscape@3x.png
│ │ │ │ ├── Default-Portrait.png
│ │ │ │ ├── Default-Portrait@2x.png
│ │ │ │ ├── Default.png
│ │ │ │ └── Default@2x.png
│ │ │ ├── LaunchScreen.AspectFill.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchScreen-AspectFill.png
│ │ │ │ └── LaunchScreen-AspectFill@2x.png
│ │ │ └── LaunchScreen.Center.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── LaunchScreen-Center.png
│ │ │ │ └── LaunchScreen-Center@2x.png
│ │ │ ├── Info.plist
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── build.xcconfig
│ ├── assets
│ │ └── demo-screenshot.png
│ ├── main.ts
│ ├── package.json
│ └── views
│ │ └── Home.vue
├── babel.config.js
├── nsconfig.json
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── favicon.ico
│ └── index.html
├── tsconfig.json
├── types
│ ├── globals.d.ts
│ ├── shims-tsx.d.ts
│ └── shims-vue.d.ts
├── vue.config.js
└── webpack.config.js
├── dist
├── nativescript-vue-shadow.esm.js
├── nativescript-vue-shadow.js
└── nativescript-vue-shadow.umd.js
├── jest.config.js
├── package-lock.json
├── package.json
├── src
├── common
│ ├── android-data.model.ts
│ ├── elevation.enum.ts
│ ├── index.ts
│ ├── ios-data.model.ts
│ ├── shadow.ts
│ └── shape.enum.ts
├── index.ts
└── vue-shadow.ts
├── tests
└── unit
│ ├── .eslintrc.js
│ ├── example.spec.ts
│ └── plugin.spec.ts
├── tsconfig.json
└── types
├── common
├── android-data.model.d.ts
├── elevation.enum.d.ts
├── index.d.ts
├── ios-data.model.d.ts
├── shadow.d.ts
└── shape.enum.d.ts
├── index.d.ts
├── vue-shadow.d.ts
└── vue-shims.d.ts
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // https://eslint.org/docs/user-guide/configuring#using-configuration-files-1
3 | root: true,
4 |
5 | // https://eslint.org/docs/user-guide/configuring#specifying-environments
6 | env: {
7 | browser: true,
8 | node: true
9 | },
10 |
11 | // https://eslint.org/docs/user-guide/configuring#specifying-parser
12 | parser: 'vue-eslint-parser',
13 | // https://vuejs.github.io/eslint-plugin-vue/user-guide/#faq
14 | parserOptions: {
15 | parser: '@typescript-eslint/parser',
16 | ecmaVersion: 2017,
17 | sourceType: 'module',
18 | project: './tsconfig.json'
19 | },
20 |
21 | // https://eslint.org/docs/user-guide/configuring#extending-configuration-files
22 | // order matters: from least important to most important in terms of overriding
23 | // Prettier + Vue: https://medium.com/@gogl.alex/how-to-properly-set-up-eslint-with-prettier-for-vue-or-nuxt-in-vscode-e42532099a9c
24 | extends: [
25 | 'eslint:recommended',
26 | 'plugin:@typescript-eslint/recommended',
27 | 'plugin:vue/recommended',
28 | 'prettier',
29 | 'prettier/vue',
30 | 'prettier/@typescript-eslint'
31 | ],
32 |
33 |
34 | // https://eslint.org/docs/user-guide/configuring#configuring-plugins
35 | plugins: ['vue', '@typescript-eslint'],
36 |
37 |
38 |
39 | "rules": {
40 | "import/extensions": 0,
41 | "global-require": 0,
42 | "eol-last": 0,
43 | "no-param-reassign": 0,
44 | "object-curly-newline": 0,
45 | "no-plusplus": 0,
46 | "no-console": "off",
47 | "no-implicity-any": "off",
48 | "no-explicity-any": "off",
49 | "vue/valid-template-root": "off",
50 | "max-len": [
51 | 2,
52 | {
53 | "code": 160
54 | }
55 | ],
56 | "prefer-destructuring": [
57 | 2,
58 | {
59 | "object": true,
60 | "array": false
61 | }
62 | ],
63 | "@typescript-eslint/no-empty-interface": 1,
64 | // https://github.com/typescript-eslint/typescript-eslint/issues/103
65 | "@typescript-eslint/no-parameter-properties": 0
66 | },
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | .DS_Store
64 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 200,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "tabWidth": 2,
6 | "semicolons": true,
7 | "bracketSpacing": true,
8 | "arrowParens": "always",
9 | "useTabs": false
10 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | // TODO: release log here ...
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Gary Gambill
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 | # Nativescript-Vue Shadow Directive Plugin  
2 |
3 | [![NPM version][npm-image]][npm-url]
4 | [![Downloads][downloads-image]][npm-url]
5 | [![Twitter Follow][twitter-image]][twitter-url]
6 |
7 | [npm-image]: http://img.shields.io/npm/v/nativescript-vue-shadow.svg
8 | [npm-url]: https://npmjs.org/package/nativescript-vue-shadow
9 | [downloads-image]: http://img.shields.io/npm/dt/nativescript-vue-shadow.svg
10 | [twitter-image]: https://img.shields.io/twitter/follow/Jawa_the_Hutt.svg?style=social&label=Jawa_the_hutt
11 | [twitter-url]: https://twitter.com/Jawa_the_Hutt
12 |
13 | This repo is a port to Nativescript-Vue of @JoshDSommer's [NativeScript Angular Shadow Directive project](https://github.com/JoshDSommer/nativescript-ngx-shadow). As such, a good portion of the code is inspired by it, but many changes were made to fit into how Vue does Directives.
14 |
15 | ## Installation
16 |
17 | From the command prompt go to your app's root folder and execute:
18 |
19 | ``` bash
20 | npm install nativescript-vue-shadow
21 | ```
22 |
23 | ## Demo
24 |
25 | 
26 |
27 | ### How to use it
28 |
29 | This is a Vue directive to make your life easier when it comes to using native shadows with Nativescript-Vue.
30 |
31 | Shadows are a very important part of [Material design specification](https://material.io/).
32 | It brings up the [concept of elevation](https://material.io/guidelines/material-design/elevation-shadows.html), which implies in the natural human way of perceiving objects raising up from the surface.
33 |
34 | With this directive, you won't have to worry about all the aspects regarding shadowing on Android and on iOS. On the other hand, if you care about some of the details, you will still be able to provide certain extra attributes and they will superseed the default ones.
35 |
36 | However, running this on Android you will require the SDK to be greater or equal than 21 (Android 5.0 Lollipop or later), otherwise shadows will simply not be shown. There should be no problem running this on any version of iOS.
37 |
38 | #### Import the Directive into main.js
39 |
40 | ```typescript
41 | import NSVueShadow from 'nativescript-vue-shadow'
42 | Vue.use(NSVueShadow)
43 | ```
44 |
45 | #### Use in your view or component
46 |
47 | Simple attribute for `v-shadow`:
48 |
49 | ```html
50 |
51 | ```
52 |
53 | You can property bind it in your `template` tag. This can be a `string`, `number` or `object` ( [AndroidData](https://github.com/jawa-the-hutt/nativescript-vue-shadow/blob/master/src/common/android-data.model.ts) \| [IOSData](https://github.com/jawa-the-hutt/nativescript-vue-shadow/blob/master/src/common/ios-data.model.ts) ):
54 |
55 | ```html
56 |
57 | ```
58 |
59 | Then in your `script` tag you can do something like this where we bind to the object:
60 |
61 | ```typescript
62 | import { AndroidData, ShapeEnum } from "nativescript-vue-shadow";
63 | // ...
64 | export default class MyComponent extends Vue {
65 | private myCustomData: AndroidData = {
66 | elevation: 6,
67 | bgcolor: "#ff1744",
68 | shape: ShapeEnum.OVAL
69 | };
70 | // ...
71 | }
72 | ```
73 |
74 | You can also provide details directly in your markup by using the `v-shadow` directive with an explicit object ( [AndroidData](https://github.com/jawa-the-hutt/nativescript-vue-shadow/blob/master/src/common/android-data.model.ts) \| [IOSData](https://github.com/jawa-the-hutt/nativescript-vue-shadow/blob/master/src/common/ios-data.model.ts) ):
75 |
76 | ```html
77 |
78 | ```
79 |
80 | There are a couple of platform specific attributes you might want to use to customize your view. Bear in mind some of them clash with CSS styles applied to the same views. When it happens, the default behaviour on Android is the original HTML/CSS styles are lost in favor of the ones provided by this directive. On iOS, on the other hand, HTML/CSS pre-existent styles are regarded, consequently the shadow might not be applied.
81 |
82 | The tip is avoid applying things like **background color** and **border radius** to the same view you intend to apply this directive (Note: this is now supported).
83 |
84 | ### List of attributes
85 |
86 | The table below list and describes all possible attributes as well as show which platform supports each one of them:
87 |
88 | | Attribute | Type | Default | Platform | Description |
89 | | -------------------- | ---------------- | -------- | ---------- |--------------- |
90 | | elevation | number \| string | | both | Determines the elevation of the view from the surface. It does all shadow related calculations. You might want to have a look at [this enum](https://github.com/jawa-the-hutt/nativescript-vue-shadow/blob/master/src/common/elevation.enum.ts) of standard material design elevations. FYI, it's calculated in DIPs (or DPs, _density independent pixels_) on Android, or PTs (_points_) on iOS. |
91 | | pressedElevation | number \| string | | Android | Determines the view's elevation when on pressed state. |
92 | | shape | string => `'RECTANGLE'` \| `'OVAL'` \| `'RING'` \| `'LINE'` | `'RECTANGLE'` | Android | Determines the shape of the view and overrides its format styles. |
93 | | bgcolor | string (#RGB) | | Android | Determines view's background color and overrides its previous background. If not set, the previous background is used. **NOTE:** setting the background to transparent is known to cause issues on Android (the shadow may overlap the background) |
94 | | cornerRadius | number | | Android | Determines view's corner radius _(CSS border-radius)_ and overrides its previous style. If this is not set, the view's CSS border-radius are used. FYI, it's calculated in DIPs (or DPs, _density independent pixels_). |
95 | | translationZ | number | | Android | Determines an extra distance (in DIP) to the surface. |
96 | | pressedTranslationZ | number | | Android | Determines an extra distance (in DIP) to the surface when the view is in the pressed state. |
97 | | forcePressAnimation | boolean | false | Android | By default, if a view has a StateAnimator, it is overwritten by an animator that raises the View on press. Setting this to true will always define this new animator, essentially making any clickable View work as a button. |
98 | | maskToBounds | boolean | false | iOS | Determines whether the shadow will be limited to the view margins. |
99 | | shadowColor | string (#RGB) | | iOS | Determines shadow color. Shadow won't be applied if the view already has background. |
100 | | shadowOffset | number | | iOS | Determines the distance in points (only on Y axis) of the shadow. Negative value shows the shadow above the view. |
101 | | shadowOpacity | number | | iOS | From 0 to 1. Determines the opacity level of the shadow. |
102 | | shadowRadius | number | | iOS | Determines the blurring effect in points of the shadow. The higher the more blurred. |
103 | | useShadowPath | boolean | true | iOS | Determines whether to use shadowPath to render the shadow. Setting this to false negatively impacts performance. |
104 | | rasterize | boolean | false | iOS | Determines whether the view should be rasterized. Activating this will increase memory usage, as rasterized views are stored in memory, but will massively improve performance. |
105 |
106 | ## Pre-defined elevations
107 |
108 | If you want to be consistent with the Material Design specification but you're sick of trying to memorize which elevation your view should have. We've put together a list of pre-defined elevations:
109 |
110 | - SWITCH: 1
111 | - CARD_RESTING: 2
112 | - RAISED_BUTTON_RESTING: 2
113 | - SEARCH_BAR_RESTING: 2
114 | - REFRESH_INDICADOR: 3
115 | - SEARCH_BAR_SCROLLED: 3
116 | - APPBAR: 4
117 | - FAB_RESTING: 6
118 | - SNACKBAR: 6
119 | - BOTTOM_NAVIGATION_BAR: 8
120 | - MENU: 8
121 | - CARD_PICKED_UP: 8,
122 | - RAISED_BUTTON_PRESSED: 8
123 | - SUBMENU_LEVEL1: 9
124 | - SUBMENU_LEVEL2: 10
125 | - SUBMENU_LEVEL3: 11
126 | - SUBMENU_LEVEL4: 12
127 | - SUBMENU_LEVEL5: 13
128 | - FAB_PRESSED: 12
129 | - NAV_DRAWER: 16
130 | - RIGHT_DRAWER: 16
131 | - MODAL_BOTTOM_SHEET: 16
132 | - DIALOG: 24
133 | - PICKER: 24
134 |
135 | If you don't even want to check it out every time you have to shadow an element, just import the `Elevation` enum and enjoy :)
136 |
137 | #### Component
138 |
139 | ```typescript
140 | import { Elevation } from "nativescript-vue-shadow";
141 |
142 | export default class MyComponent extends Vue {
143 | // ...
144 | private elevation: number = Elevation.SNACKBAR;
145 | // ...
146 | }
147 | ```
148 |
149 | ### Override Android default StateListAnimator
150 |
151 | Android buttons are split into three categories: floating, raised and flat. Different from labels and other ui elements, each button category has its own state animator. So, when buttons are tapped, Android does affect their elevation (and z translation) in a way that Angular is not notified. At the end of tap animation, buttons get back to resting defaults (i.e. raised button's `elevation` at 2dp and `translationZ` at 0) overriding the shadow stablished by this plugin.
152 |
153 | This plugin replaces the default `StateListAnimator` with one that gets back to the values you provide for `elevation` and `translationZ`.
154 |
155 | Feel free to fill submit a PR if you want the flexibility of defining your own `StateListAnimator`. The motivation so far was simply put this plugin to work with buttons without changing the original state once they are clicked.
156 |
157 | It's also possible to set this `StateListAnimator` to any View, making it behave like a button.
158 |
159 | ## Plugin Development Work Flow
160 |
161 | - Clone repository to your machine.
162 | - Run `npm install` in base directory of project
163 | - Change to Demo directory and then run `npm install`
164 | - Run and deploy to your device or emulator with `npm run serve:android` or `npm run serve:ios`. (use `debug:android` or `debug:ios` to attach to devtools)
165 |
166 | ## Changelog
167 |
168 | - 0.1.0 Initial implementation
169 |
170 | ## License
171 |
172 | MIT License
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | target: "node"
7 | },
8 | "@babel/preset-es2015"
9 | ]
10 | ],
11 | plugins: ["@babel/plugin-syntax-dynamic-import"],
12 | retainLines: true,
13 | comments: true
14 | };
15 |
--------------------------------------------------------------------------------
/build/rollup.config.js:
--------------------------------------------------------------------------------
1 | // rollup.config.js
2 | import vue from "rollup-plugin-vue";
3 | import commonjs from "rollup-plugin-commonjs";
4 | import replace from "rollup-plugin-replace";
5 | import { terser } from "rollup-plugin-terser";
6 | import typescript from "rollup-plugin-typescript2";
7 | import minimist from "minimist";
8 | import resolve from "rollup-plugin-node-resolve";
9 |
10 | const argv = minimist(process.argv.slice(2));
11 |
12 | const baseConfig = {
13 | input: "src/index.ts",
14 | inlineDynamicImports: true,
15 | plugins: [
16 | replace({
17 | "process.env.NODE_ENV": JSON.stringify("production")
18 | }),
19 | resolve(),
20 | commonjs(),
21 | typescript({
22 | tsconfig: "tsconfig.json",
23 | useTsconfigDeclarationDir: true,
24 | objectHashIgnoreUnknownHack: true,
25 | clean: true
26 | }),
27 | vue({
28 | css: true,
29 | compileTemplate: true,
30 | template: {
31 | isProduction: true
32 | }
33 | })
34 | ]
35 | };
36 |
37 | // UMD/IIFE shared settings: externals and output.globals
38 | // Refer to https://rollupjs.org/guide/en#output-globals for details
39 | const external = [
40 | // list external dependencies, exactly the way it is written in the import statement.
41 | // eg. 'jquery'
42 | "nativescript-vue",
43 | "tns-core-modules/color",
44 | "tns-core-modules/platform",
45 | "tns-core-modules/ui/page/page",
46 | "tns-core-modules/ui/core/weak-event-listener",
47 | "'tns-core-modules/ui/layouts/stack-layout"
48 | ];
49 | const globals = {
50 | // Provide global variable names to replace your external imports
51 | // eg. jquery: '$'
52 | "nativescript-vue": 'vue',
53 | "tns-core-modules/color": 'color',
54 | "tns-core-modules/platform": 'platform',
55 | "tns-core-modules/ui/page/page": 'page',
56 | "tns-core-modules/ui/core/weak-event-listener" : 'weakEventListener',
57 | };
58 |
59 | // Customize configs for individual targets
60 | const buildFormats = [];
61 | if (!argv.format || argv.format === "es") {
62 | const esConfig = {
63 | ...baseConfig,
64 | external,
65 | output: {
66 | file: "dist/nativescript-vue-shadow.esm.js",
67 | format: "esm",
68 | exports: "named"
69 | },
70 | plugins: [
71 | ...baseConfig.plugins
72 | // terser({
73 | // output: {
74 | // ecma: 6
75 | // }
76 | // })
77 | ]
78 | };
79 | buildFormats.push(esConfig);
80 | }
81 |
82 | if (!argv.format || argv.format === "umd") {
83 | const umdConfig = {
84 | ...baseConfig,
85 | external,
86 | output: {
87 | compact: true,
88 | file: "dist/nativescript-vue-shadow.umd.js",
89 | format: "umd",
90 | name: "NativescriptVueshadow",
91 | exports: "named",
92 | globals
93 | },
94 | plugins: [
95 | ...baseConfig.plugins
96 | // terser({
97 | // output: {
98 | // ecma: 6
99 | // }
100 | // })
101 | ]
102 | };
103 | buildFormats.push(umdConfig);
104 | }
105 |
106 | if (!argv.format || argv.format === "iife") {
107 | const unpkgConfig = {
108 | ...baseConfig,
109 | external,
110 | output: {
111 | compact: true,
112 | file: "dist/nativescript-vue-shadow.js",
113 | format: "iife",
114 | name: "NativescriptVueshadow",
115 | exports: "named",
116 | globals
117 | },
118 | plugins: [
119 | ...baseConfig.plugins
120 | // terser({
121 | // output: {
122 | // ecma: 5
123 | // }
124 | // })
125 | ]
126 | };
127 | buildFormats.push(unpkgConfig);
128 | }
129 |
130 | // Export config
131 | export default buildFormats;
132 |
--------------------------------------------------------------------------------
/demo/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/demo/.env.development.android:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | VUE_APP_PLATFORM=android
3 | VUE_APP_MODE=native
--------------------------------------------------------------------------------
/demo/.env.development.ios:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | VUE_APP_PLATFORM=ios
3 | VUE_APP_MODE=native
--------------------------------------------------------------------------------
/demo/.env.development.web:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | VUE_APP_PLATFORM=web
3 | VUE_APP_MODE=web
--------------------------------------------------------------------------------
/demo/.env.production.android:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VUE_APP_PLATFORM=android
3 | VUE_APP_MODE=native
--------------------------------------------------------------------------------
/demo/.env.production.ios:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VUE_APP_PLATFORM=ios
3 | VUE_APP_MODE=native
--------------------------------------------------------------------------------
/demo/.env.production.web:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VUE_APP_PLATFORM=web
3 | VUE_APP_MODE=web
--------------------------------------------------------------------------------
/demo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 |
4 | env: {
5 | node: true
6 | },
7 |
8 | extends: ['plugin:vue/essential', '@vue/prettier', '@vue/typescript'],
9 |
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
13 | },
14 |
15 | parserOptions: {
16 | parser: '@typescript-eslint/parser'
17 | },
18 |
19 | globals: {
20 | TNS_APP_MODE: true,
21 | TNS_APP_PLATFORM: true
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
23 | # NativeScript application
24 | hooks
25 | platforms
26 | ./webpack.config.js
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # demo
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | npm run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | npm run lint
26 | ```
27 |
28 | ### Customize configuration
29 | See [Configuration Reference](https://cli.vuejs.org/config/).
30 |
--------------------------------------------------------------------------------
/demo/app/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/app.gradle:
--------------------------------------------------------------------------------
1 | // Add your native dependencies here:
2 |
3 | android {
4 | defaultConfig {
5 | generatedDensities = []
6 | applicationId = "org.nativescript.application"
7 | }
8 | aaptOptions {
9 | additionalParameters "--no-version-vectors"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-hdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-hdpi/background.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-hdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-hdpi/logo.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-ldpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-ldpi/background.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-ldpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-ldpi/logo.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-mdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-mdpi/background.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-mdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-mdpi/logo.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-nodpi/splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 | -
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xhdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xhdpi/background.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xhdpi/logo.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xxhdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xxhdpi/background.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xxhdpi/logo.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xxxhdpi/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xxxhdpi/background.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xxxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xxxhdpi/icon.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/drawable-xxxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/Android/drawable-xxxhdpi/logo.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/values-v21/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3d5afe
4 |
5 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/values-v21/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | demo
4 | demo
5 |
6 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
14 |
15 |
16 |
19 |
20 |
23 |
24 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F5F5F5
4 | #757575
5 | #33B5E5
6 | #272734
7 |
8 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | demo
4 | demo
5 |
6 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/Android/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
20 |
21 |
22 |
29 |
30 |
32 |
33 |
34 |
39 |
40 |
42 |
43 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "icon-29.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "icon-29@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "icon-29@3x.png",
19 | "scale" : "3x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "icon-40@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "icon-40@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "icon-60@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "icon-60@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "icon-29.png",
49 | "scale" : "1x"
50 | },
51 | {
52 | "size" : "29x29",
53 | "idiom" : "ipad",
54 | "filename" : "icon-29@2x.png",
55 | "scale" : "2x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "icon-40.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "40x40",
65 | "idiom" : "ipad",
66 | "filename" : "icon-40@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "icon-76.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "76x76",
77 | "idiom" : "ipad",
78 | "filename" : "icon-76@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "83.5x83.5",
83 | "idiom" : "ipad",
84 | "filename" : "icon-83.5@2x.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "1024x1024",
89 | "idiom" : "ios-marketing",
90 | "filename" : "icon-1024.png",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "extent" : "full-screen",
5 | "idiom" : "iphone",
6 | "subtype" : "2436h",
7 | "filename" : "Default-1125h.png",
8 | "minimum-system-version" : "11.0",
9 | "orientation" : "portrait",
10 | "scale" : "3x"
11 | },
12 | {
13 | "orientation" : "landscape",
14 | "idiom" : "iphone",
15 | "extent" : "full-screen",
16 | "filename" : "Default-Landscape-X.png",
17 | "minimum-system-version" : "11.0",
18 | "subtype" : "2436h",
19 | "scale" : "3x"
20 | },
21 | {
22 | "extent" : "full-screen",
23 | "idiom" : "iphone",
24 | "subtype" : "736h",
25 | "filename" : "Default-736h@3x.png",
26 | "minimum-system-version" : "8.0",
27 | "orientation" : "portrait",
28 | "scale" : "3x"
29 | },
30 | {
31 | "extent" : "full-screen",
32 | "idiom" : "iphone",
33 | "subtype" : "736h",
34 | "filename" : "Default-Landscape@3x.png",
35 | "minimum-system-version" : "8.0",
36 | "orientation" : "landscape",
37 | "scale" : "3x"
38 | },
39 | {
40 | "extent" : "full-screen",
41 | "idiom" : "iphone",
42 | "subtype" : "667h",
43 | "filename" : "Default-667h@2x.png",
44 | "minimum-system-version" : "8.0",
45 | "orientation" : "portrait",
46 | "scale" : "2x"
47 | },
48 | {
49 | "orientation" : "portrait",
50 | "idiom" : "iphone",
51 | "filename" : "Default@2x.png",
52 | "extent" : "full-screen",
53 | "minimum-system-version" : "7.0",
54 | "scale" : "2x"
55 | },
56 | {
57 | "extent" : "full-screen",
58 | "idiom" : "iphone",
59 | "subtype" : "retina4",
60 | "filename" : "Default-568h@2x.png",
61 | "minimum-system-version" : "7.0",
62 | "orientation" : "portrait",
63 | "scale" : "2x"
64 | },
65 | {
66 | "orientation" : "portrait",
67 | "idiom" : "ipad",
68 | "filename" : "Default-Portrait.png",
69 | "extent" : "full-screen",
70 | "minimum-system-version" : "7.0",
71 | "scale" : "1x"
72 | },
73 | {
74 | "orientation" : "landscape",
75 | "idiom" : "ipad",
76 | "filename" : "Default-Landscape.png",
77 | "extent" : "full-screen",
78 | "minimum-system-version" : "7.0",
79 | "scale" : "1x"
80 | },
81 | {
82 | "orientation" : "portrait",
83 | "idiom" : "ipad",
84 | "filename" : "Default-Portrait@2x.png",
85 | "extent" : "full-screen",
86 | "minimum-system-version" : "7.0",
87 | "scale" : "2x"
88 | },
89 | {
90 | "orientation" : "landscape",
91 | "idiom" : "ipad",
92 | "filename" : "Default-Landscape@2x.png",
93 | "extent" : "full-screen",
94 | "minimum-system-version" : "7.0",
95 | "scale" : "2x"
96 | },
97 | {
98 | "orientation" : "portrait",
99 | "idiom" : "iphone",
100 | "filename" : "Default.png",
101 | "extent" : "full-screen",
102 | "scale" : "1x"
103 | },
104 | {
105 | "orientation" : "portrait",
106 | "idiom" : "iphone",
107 | "filename" : "Default@2x.png",
108 | "extent" : "full-screen",
109 | "scale" : "2x"
110 | },
111 | {
112 | "orientation" : "portrait",
113 | "idiom" : "iphone",
114 | "filename" : "Default-568h@2x.png",
115 | "extent" : "full-screen",
116 | "subtype" : "retina4",
117 | "scale" : "2x"
118 | },
119 | {
120 | "orientation" : "portrait",
121 | "idiom" : "ipad",
122 | "extent" : "to-status-bar",
123 | "scale" : "1x"
124 | },
125 | {
126 | "orientation" : "portrait",
127 | "idiom" : "ipad",
128 | "filename" : "Default-Portrait.png",
129 | "extent" : "full-screen",
130 | "scale" : "1x"
131 | },
132 | {
133 | "orientation" : "landscape",
134 | "idiom" : "ipad",
135 | "extent" : "to-status-bar",
136 | "scale" : "1x"
137 | },
138 | {
139 | "orientation" : "landscape",
140 | "idiom" : "ipad",
141 | "filename" : "Default-Landscape.png",
142 | "extent" : "full-screen",
143 | "scale" : "1x"
144 | },
145 | {
146 | "orientation" : "portrait",
147 | "idiom" : "ipad",
148 | "extent" : "to-status-bar",
149 | "scale" : "2x"
150 | },
151 | {
152 | "orientation" : "portrait",
153 | "idiom" : "ipad",
154 | "filename" : "Default-Portrait@2x.png",
155 | "extent" : "full-screen",
156 | "scale" : "2x"
157 | },
158 | {
159 | "orientation" : "landscape",
160 | "idiom" : "ipad",
161 | "extent" : "to-status-bar",
162 | "scale" : "2x"
163 | },
164 | {
165 | "orientation" : "landscape",
166 | "idiom" : "ipad",
167 | "filename" : "Default-Landscape@2x.png",
168 | "extent" : "full-screen",
169 | "scale" : "2x"
170 | }
171 | ],
172 | "info" : {
173 | "version" : 1,
174 | "author" : "xcode"
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-1125h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-1125h.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-X.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape-X.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchScreen-AspectFill.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchScreen-AspectFill@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchScreen-Center.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchScreen-Center@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | demo
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 0.1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 0.1.0
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiresFullScreen
28 |
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/demo/app/App_Resources/iOS/build.xcconfig:
--------------------------------------------------------------------------------
1 | // You can add custom settings here
2 | // for example you can uncomment the following line to force distribution code signing
3 | // CODE_SIGN_IDENTITY = iPhone Distribution
4 | // To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html
5 | // DEVELOPMENT_TEAM = YOUR_TEAM_ID;
6 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
7 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
8 |
--------------------------------------------------------------------------------
/demo/app/assets/demo-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/app/assets/demo-screenshot.png
--------------------------------------------------------------------------------
/demo/app/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'nativescript-vue';
2 | import App from './App.vue';
3 |
4 | import NSVueShadow from '../../'
5 | Vue.use(NSVueShadow)
6 |
7 | // Set the following to `true` to hide the logs created by nativescript-vue
8 | Vue.config.silent = false;
9 | // Set the following to `false` to not colorize the logs created by nativescript-vue
10 | // disabled in template due to typing issue for Typescript projects....NEEDS TO BE FIXED
11 | // @ts-ignore
12 | Vue.config.debug = true;
13 |
14 | // setup NS-Vue Devtools for use
15 | import VueDevtools from 'nativescript-vue-devtools';
16 | Vue.use(VueDevtools, { host: '10.0.2.2' });
17 |
18 | new Vue({
19 | render: h => h('frame', [h(App)]),
20 | }).$start();
21 |
--------------------------------------------------------------------------------
/demo/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "android": {
3 | "v8Flags": "--expose_gc",
4 | "markingMode": "none"
5 | },
6 | "main": "main",
7 | "name": "demo",
8 | "version": "0.1.0"
9 | }
10 |
--------------------------------------------------------------------------------
/demo/app/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
99 |
100 |
133 |
--------------------------------------------------------------------------------
/demo/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | '@babel/plugin-syntax-dynamic-import'
4 | ],
5 | presets: [
6 | process.env.VUE_PLATFORM === 'web' ? '@vue/app' : {},
7 | ['@babel/env', { targets: { esmodules: true } }]
8 | ]
9 | }
--------------------------------------------------------------------------------
/demo/nsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "appPath": "app",
3 | "appResourcesPath": "app/App_Resources"
4 | }
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "lint": "vue-cli-service lint",
7 | "build:android": "npm run setup-webpack-config && tns build android --bundle --env.production && npm run remove-webpack-config",
8 | "build:ios": "npm run setup-webpack-config && tns build ios --bundle --env.production && npm run remove-webpack-config",
9 | "build:web": "vue-cli-service build --mode production.web",
10 | "clean:android": "rimraf platforms/android",
11 | "clean:ios": "rimraf platforms/ios",
12 | "clean:platforms": "rimraf platforms",
13 | "debug:android": "npm run setup-webpack-config && tns debug android --bundle --env.development",
14 | "debug:ios": "npm run setup-webpack-config && tns debug ios --bundle --env.development",
15 | "preview:android": "npm run setup-webpack-config && tns preview --bundle --env.development --env.android",
16 | "preview:ios": "npm run setup-webpack-config && tns preview --bundle --env.development --env.ios",
17 | "remove-webpack-config": "node ./node_modules/vue-cli-plugin-nativescript-vue/lib/scripts/webpack-maintenance post",
18 | "serve:android": "npm run setup-webpack-config && tns run android --bundle --env.development",
19 | "serve:ios": "npm run setup-webpack-config && tns run ios --bundle --env.development",
20 | "serve:web": "vue-cli-service serve --mode development.web",
21 | "setup-webpack-config": "node ./node_modules/vue-cli-plugin-nativescript-vue/lib/scripts/webpack-maintenance pre"
22 | },
23 | "dependencies": {
24 | "@vue/devtools": "^5.0.9",
25 | "core-js": "^3.0.1",
26 | "nativescript-socketio": "^3.2.1",
27 | "nativescript-toasty": "^1.3.0",
28 | "nativescript-vue": "^2.2.2",
29 | "nativescript-vue-devtools": "^1.2.0",
30 | "tns-core-modules": "^5.3.1",
31 | "vue": "^2.6.10",
32 | "vue-class-component": "^7.0.2",
33 | "vue-property-decorator": "^8.1.0"
34 | },
35 | "devDependencies": {
36 | "@babel/core": "^7.4.0",
37 | "@babel/preset-env": "^7.4.1",
38 | "@babel/traverse": "^7.4.0",
39 | "@babel/types": "^7.4.0",
40 | "@vue/cli-plugin-babel": "^3.6.0",
41 | "@vue/cli-plugin-eslint": "^3.6.0",
42 | "@vue/cli-plugin-typescript": "^3.6.0",
43 | "@vue/cli-service": "^3.6.0",
44 | "@vue/eslint-config-prettier": "^4.0.1",
45 | "@vue/eslint-config-typescript": "^4.0.0",
46 | "babel-eslint": "^10.0.1",
47 | "babel-loader": "^8.0.5",
48 | "eslint": "^5.16.0",
49 | "eslint-plugin-vue": "^5.0.0",
50 | "fork-ts-checker-webpack-plugin": "^1.0.0",
51 | "nativescript-dev-webpack": "^0.21.2",
52 | "nativescript-vue-template-compiler": "^2.2.2",
53 | "nativescript-worker-loader": "~0.9.5",
54 | "node-sass": "^4.11.0",
55 | "rimraf": "^2.6.3",
56 | "sass-loader": "^7.1.0",
57 | "string-replace-loader": "^2.1.1",
58 | "terser-webpack-plugin": "^1.2.3",
59 | "typescript": "^3.4.3",
60 | "vue-cli-plugin-nativescript-vue": "0.0.14",
61 | "vue-template-compiler": "^2.6.10",
62 | "webpack": "^4.29.6",
63 | "webpack-cli": "^3.3.0"
64 | },
65 | "nativescript": {
66 | "id": "org.nativescript.application",
67 | "tns-ios": {
68 | "version": "5.3.0"
69 | },
70 | "tns-android": {
71 | "version": "5.3.0"
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/demo/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawa-the-hutt/nativescript-vue-shadow/bbb5d17d0540c99de58590207337c72fd98e36f0/demo/public/favicon.ico
--------------------------------------------------------------------------------
/demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | demo
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "experimentalDecorators": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": [
15 | "node"
16 | ],
17 | "paths": {
18 | "@/*": [
19 | "app/*"
20 | ],
21 | "assets/*": [
22 | "app/assets/*"
23 | ],
24 | "fonts/*": [
25 | "app/fonts/*"
26 | ],
27 | "components/*": [
28 | "app/components/*"
29 | ],
30 | "styles/*": [
31 | "app/styles/*"
32 | ],
33 | "app/*": [
34 | "app/*"
35 | ]
36 | },
37 | "lib": [
38 | "esnext",
39 | "dom",
40 | "dom.iterable",
41 | "scripthost"
42 | ],
43 | "noImplicitAny": false
44 | },
45 | "include": [
46 | "app/**/*.ts",
47 | "app/**/*.tsx",
48 | "app/**/*.vue",
49 | "tests/**/*.ts",
50 | "tests/**/*.tsx",
51 | "types/**/*.d.ts"
52 | ],
53 | "exclude": [
54 | "node_modules"
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/demo/types/globals.d.ts:
--------------------------------------------------------------------------------
1 | declare const TNS_ENV: string;
2 | declare const TNS_APP_PLATFORM: string;
3 | declare const TNS_APP_MODE: string;
--------------------------------------------------------------------------------
/demo/types/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue';
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo/types/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue';
3 | export default Vue;
4 | }
5 |
--------------------------------------------------------------------------------
/demo/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | chainWebpack: (config) => {
3 | // for debugging the project
4 | config.devtool('inline-source-map');
5 | },
6 | runtimeCompiler: true
7 | };
8 |
--------------------------------------------------------------------------------
/demo/webpack.config.js:
--------------------------------------------------------------------------------
1 | // this file is for cases where we need to access the
2 | // webpack config as a file when using CLI commands.
3 |
4 | let service = process.VUE_CLI_SERVICE
5 |
6 | if (!service || process.env.VUE_CLI_API_MODE) {
7 | const Service = require('@vue/cli-service/lib/Service')
8 | service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
9 | service.init(process.env.VUE_CLI_MODE || process.env.NODE_ENV)
10 | }
11 |
12 | module.exports = service.resolveWebpackConfig()
13 |
--------------------------------------------------------------------------------
/dist/nativescript-vue-shadow.esm.js:
--------------------------------------------------------------------------------
1 | import Vue from 'nativescript-vue';
2 | import { isAndroid, screen, isIOS } from 'tns-core-modules/platform';
3 | import { Color } from 'tns-core-modules/color';
4 | import { Length, View } from 'tns-core-modules/ui/page/page';
5 | import { addWeakEventListener, removeWeakEventListener } from 'tns-core-modules/ui/core/weak-event-listener';
6 |
7 | var ShapeEnum;
8 | (function (ShapeEnum) {
9 | ShapeEnum["RECTANGLE"] = "RECTANGLE";
10 | ShapeEnum["OVAL"] = "OVAL";
11 | ShapeEnum["RING"] = "RING";
12 | ShapeEnum["LINE"] = "LINE";
13 | })(ShapeEnum || (ShapeEnum = {}));
14 |
15 | let LayeredShadow;
16 | let PlainShadow;
17 | if (isAndroid) {
18 | LayeredShadow = android.graphics.drawable.LayerDrawable.extend({});
19 | PlainShadow = android.graphics.drawable.GradientDrawable.extend({});
20 | }
21 | const classCache = {};
22 | function getAndroidR(rtype, field) {
23 | const className = "android.R$" + rtype;
24 | if (!classCache.hasOwnProperty(className)) {
25 | classCache[className] = {
26 | class: java.lang.Class.forName(className),
27 | fieldCache: {}
28 | };
29 | }
30 | if (!classCache[className].fieldCache.hasOwnProperty(field)) {
31 | classCache[className].fieldCache[field] = +classCache[className].class.getField(field).get(null);
32 | }
33 | return classCache[className].fieldCache[field];
34 | }
35 | class Shadow {
36 | static apply(tnsView, data) {
37 | const LOLLIPOP = 21;
38 | if (tnsView.android &&
39 | android.os.Build.VERSION.SDK_INT >= LOLLIPOP) {
40 | Shadow.applyOnAndroid(tnsView, Shadow.getDefaults(data));
41 | }
42 | else if (tnsView.ios) {
43 | Shadow.applyOnIOS(tnsView, Shadow.getDefaults(data));
44 | }
45 | }
46 | static getDefaults(data) {
47 | return Object.assign({}, data, {
48 | shape: data.shape || Shadow.DEFAULT_SHAPE,
49 | pressedElevation: data.pressedElevation || Shadow.DEFAULT_PRESSED_ELEVATION,
50 | pressedTranslationZ: data.pressedTranslationZ || Shadow.DEFAULT_PRESSED_ELEVATION,
51 | shadowColor: data.shadowColor ||
52 | Shadow.DEFAULT_SHADOW_COLOR,
53 | useShadowPath: (data.useShadowPath !== undefined ? data.useShadowPath : true),
54 | rasterize: (data.rasterize !== undefined ? data.rasterize : false)
55 | });
56 | }
57 | static isShadow(drawable) {
58 | return (drawable instanceof LayeredShadow || drawable instanceof PlainShadow);
59 | }
60 | static applyOnAndroid(tnsView, data) {
61 | const nativeView = tnsView.android;
62 | let shape;
63 | let overrideBackground = true;
64 | let currentBg = nativeView.getBackground();
65 | if (currentBg instanceof android.graphics.drawable.RippleDrawable) {
66 | let rippleBg = currentBg.getDrawable(0);
67 | if (rippleBg instanceof android.graphics.drawable.InsetDrawable) {
68 | overrideBackground = false;
69 | }
70 | else if (Shadow.isShadow(rippleBg)) {
71 | currentBg = rippleBg;
72 | }
73 | }
74 | if (overrideBackground) {
75 | if (Shadow.isShadow(currentBg)) {
76 | currentBg = currentBg instanceof LayeredShadow ?
77 | currentBg.getDrawable(1) : null;
78 | }
79 | const outerRadii = Array.create("float", 8);
80 | if (data.cornerRadius === undefined) {
81 | outerRadii[0] = outerRadii[1] = Length.toDevicePixels(tnsView.borderTopLeftRadius, 0);
82 | outerRadii[2] = outerRadii[3] = Length.toDevicePixels(tnsView.borderTopRightRadius, 0);
83 | outerRadii[4] = outerRadii[5] = Length.toDevicePixels(tnsView.borderBottomRightRadius, 0);
84 | outerRadii[6] = outerRadii[7] = Length.toDevicePixels(tnsView.borderBottomLeftRadius, 0);
85 | }
86 | else {
87 | java.util.Arrays.fill(outerRadii, Shadow.androidDipToPx(nativeView, data.cornerRadius));
88 | }
89 | const bgColor = currentBg ?
90 | (currentBg instanceof android.graphics.drawable.ColorDrawable && currentBg.getColor() ?
91 | currentBg.getColor() : android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR)) :
92 | android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR);
93 | let newBg;
94 | if (data.shape !== ShapeEnum.RECTANGLE || data.bgcolor || !currentBg) {
95 | shape = new PlainShadow();
96 | shape.setShape(android.graphics.drawable.GradientDrawable[data.shape]);
97 | shape.setCornerRadii(outerRadii);
98 | shape.setColor(bgColor);
99 | newBg = shape;
100 | }
101 | else {
102 | const r = new android.graphics.drawable.shapes.RoundRectShape(outerRadii, null, null);
103 | shape = new android.graphics.drawable.ShapeDrawable(r);
104 | shape.getPaint().setColor(bgColor);
105 | var arr = Array.create(android.graphics.drawable.Drawable, 2);
106 | arr[0] = shape;
107 | arr[1] = currentBg;
108 | const drawable = new LayeredShadow(arr);
109 | newBg = drawable;
110 | }
111 | nativeView.setBackgroundDrawable(newBg);
112 | }
113 | nativeView.setElevation(Shadow.androidDipToPx(nativeView, data.elevation));
114 | nativeView.setTranslationZ(Shadow.androidDipToPx(nativeView, data.translationZ));
115 | if (nativeView.getStateListAnimator() || data.forcePressAnimation) {
116 | this.overrideDefaultAnimator(nativeView, data);
117 | }
118 | }
119 | static overrideDefaultAnimator(nativeView, data) {
120 | const sla = new android.animation.StateListAnimator();
121 | const ObjectAnimator = android.animation.ObjectAnimator;
122 | const AnimatorSet = android.animation.AnimatorSet;
123 | const shortAnimTime = getAndroidR("integer", "config_shortAnimTime");
124 | const buttonDuration = nativeView.getContext().getResources().getInteger(shortAnimTime) / 2;
125 | const pressedElevation = this.androidDipToPx(nativeView, data.pressedElevation);
126 | const pressedZ = this.androidDipToPx(nativeView, data.pressedTranslationZ);
127 | const elevation = this.androidDipToPx(nativeView, data.elevation);
128 | const z = this.androidDipToPx(nativeView, data.translationZ || 0);
129 | const pressedSet = new AnimatorSet();
130 | const notPressedSet = new AnimatorSet();
131 | const defaultSet = new AnimatorSet();
132 | pressedSet.playTogether(java.util.Arrays.asList([
133 | ObjectAnimator.ofFloat(nativeView, "translationZ", [pressedZ])
134 | .setDuration(buttonDuration),
135 | ObjectAnimator.ofFloat(nativeView, "elevation", [pressedElevation])
136 | .setDuration(0),
137 | ]));
138 | notPressedSet.playTogether(java.util.Arrays.asList([
139 | ObjectAnimator.ofFloat(nativeView, "translationZ", [z])
140 | .setDuration(buttonDuration),
141 | ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
142 | .setDuration(0),
143 | ]));
144 | defaultSet.playTogether(java.util.Arrays.asList([
145 | ObjectAnimator.ofFloat(nativeView, "translationZ", [0]).setDuration(0),
146 | ObjectAnimator.ofFloat(nativeView, "elevation", [0]).setDuration(0),
147 | ]));
148 | sla.addState([getAndroidR("attr", "state_pressed"), getAndroidR("attr", "state_enabled")], pressedSet);
149 | sla.addState([getAndroidR("attr", "state_enabled")], notPressedSet);
150 | sla.addState([], defaultSet);
151 | nativeView.setStateListAnimator(sla);
152 | }
153 | static applyOnIOS(tnsView, data) {
154 | const nativeView = tnsView.ios;
155 | const elevation = parseFloat((data.elevation - 0).toFixed(2));
156 | nativeView.layer.maskToBounds = false;
157 | nativeView.layer.shadowColor = new Color(data.shadowColor).ios.CGColor;
158 | nativeView.layer.shadowOffset =
159 | data.shadowOffset ?
160 | CGSizeMake(0, parseFloat(String(data.shadowOffset))) :
161 | CGSizeMake(0, 0.54 * elevation - 0.14);
162 | nativeView.layer.shadowOpacity =
163 | data.shadowOpacity ?
164 | parseFloat(String(data.shadowOpacity)) :
165 | 0.006 * elevation + 0.25;
166 | nativeView.layer.shadowRadius =
167 | data.shadowRadius ?
168 | parseFloat(String(data.shadowRadius)) :
169 | 0.66 * elevation - 0.5;
170 | nativeView.layer.shouldRasterize = data.rasterize;
171 | nativeView.layer.rasterizationScale = screen.mainScreen.scale;
172 | let shadowPath = null;
173 | if (data.useShadowPath) {
174 | shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(nativeView.bounds, nativeView.layer.shadowRadius).cgPath;
175 | }
176 | nativeView.layer.shadowPath = shadowPath;
177 | }
178 | static androidDipToPx(nativeView, dip) {
179 | const metrics = nativeView.getContext().getResources().getDisplayMetrics();
180 | return android.util.TypedValue.applyDimension(android.util.TypedValue.COMPLEX_UNIT_DIP, dip, metrics);
181 | }
182 | }
183 | Shadow.DEFAULT_SHAPE = ShapeEnum.RECTANGLE;
184 | Shadow.DEFAULT_BGCOLOR = '#FFFFFF';
185 | Shadow.DEFAULT_SHADOW_COLOR = '#000000';
186 | Shadow.DEFAULT_PRESSED_ELEVATION = 2;
187 | Shadow.DEFAULT_PRESSED_Z = 4;
188 |
189 | class NativeShadowDirective {
190 | constructor(el, binding) {
191 | this.loaded = false;
192 | this.initialized = false;
193 | this.eventsBound = false;
194 | this.monkeyPatch = (val) => {
195 | this.previousNSFn.call(this.el._nativeView, val);
196 | this.applyShadow();
197 | };
198 | this.el = el;
199 | if (binding.value && typeof binding.value !== 'object' && (typeof binding.value === 'string' || typeof binding.value === 'number')) {
200 | this.shadow = binding.value;
201 | this.elevation = binding.value;
202 | }
203 | if (binding.value && typeof binding.value === 'object' && binding.value.elevation) {
204 | this.shadow = binding.value;
205 | this.elevation = this.shadow.elevation;
206 | if (isAndroid && (('pressedElevation' in this.shadow) ||
207 | ('shape' in this.shadow) ||
208 | ('bgcolor' in this.shadow) ||
209 | ('cornerRadius' in this.shadow) ||
210 | ('translationZ' in this.shadow) ||
211 | ('pressedTranslationZ' in this.shadow) ||
212 | ('forcePressAnimation' in this.shadow))) {
213 | this.pressedElevation = this.shadow.pressedElevation;
214 | this.shape = this.shadow.shape;
215 | this.bgcolor = this.shadow.bgcolor;
216 | this.cornerRadius = this.shadow.cornerRadius;
217 | this.translationZ = this.shadow.translationZ;
218 | this.pressedTranslationZ = this.shadow.pressedTranslationZ;
219 | this.forcePressAnimation = this.shadow.forcePressAnimation;
220 | }
221 | else if (isIOS && (('maskToBounds' in this.shadow) ||
222 | ('shadowColor' in this.shadow) ||
223 | ('shadowOffset' in this.shadow) ||
224 | ('shadowOpacity' in this.shadow) ||
225 | ('shadowRadius' in this.shadow) ||
226 | ('useShadowPath' in this.shadow) ||
227 | ('rasterize' in this.shadow))) {
228 | this.maskToBounds = this.shadow.maskToBounds;
229 | this.shadowColor = this.shadow.shadowColor;
230 | this.shadowOffset = this.shadow.shadowOffset;
231 | this.shadowOpacity = this.shadow.shadowOpacity;
232 | this.shadowRadius = this.shadow.shadowRadius;
233 | this.useShadowPath = this.shadow.useShadowPath;
234 | this.rasterize = this.shadow.rasterize;
235 | }
236 | }
237 | if (isAndroid) {
238 | if (this.el._nativeView._redrawNativeBackground) {
239 | this.originalNSFn = this.el._nativeView._redrawNativeBackground;
240 | }
241 | }
242 | }
243 | initializeCommonData() {
244 | const tShadow = typeof this.shadow;
245 | if ((tShadow === 'string' || tShadow === 'number') && !this.elevation) {
246 | this.elevation = this.shadow ? parseInt(this.shadow, 10) : 2;
247 | }
248 | const tElevation = typeof this.elevation;
249 | if (tElevation === 'string' || tElevation === 'number') {
250 | this.elevation = this.elevation ? parseInt(this.elevation, 10) : 2;
251 | }
252 | }
253 | initializeAndroidData() {
254 | if (typeof this.cornerRadius === 'string') {
255 | this.cornerRadius = parseInt(this.cornerRadius, 10);
256 | }
257 | if (typeof this.translationZ === 'string') {
258 | this.translationZ = parseInt(this.translationZ, 10);
259 | }
260 | }
261 | initializeIOSData() {
262 | if (typeof this.shadowOffset === 'string') {
263 | this.shadowOffset = parseFloat(this.shadowOffset);
264 | }
265 | if (typeof this.shadowOpacity === 'string') {
266 | this.shadowOpacity = parseFloat(this.shadowOpacity);
267 | }
268 | if (typeof this.shadowRadius === 'string') {
269 | this.shadowRadius = parseFloat(this.shadowRadius);
270 | }
271 | }
272 | bindEvents() {
273 | if (!this.eventsBound) {
274 | addWeakEventListener(this.el._nativeView, View.loadedEvent, this.load, this);
275 | addWeakEventListener(this.el._nativeView, View.unloadedEvent, this.unload, this);
276 | this.eventsBound = true;
277 | if (this.el._nativeView.isLoaded) {
278 | this.load();
279 | }
280 | }
281 | }
282 | unbindEvents() {
283 | if (this.eventsBound) {
284 | removeWeakEventListener(this.el._nativeView, View.loadedEvent, this.load, this);
285 | removeWeakEventListener(this.el._nativeView, View.unloadedEvent, this.unload, this);
286 | this.eventsBound = false;
287 | }
288 | }
289 | load() {
290 | this.loaded = true;
291 | this.applyShadow();
292 | if (isAndroid) {
293 | this.previousNSFn = this.el._nativeView._redrawNativeBackground;
294 | this.el._nativeView._redrawNativeBackground = this.monkeyPatch;
295 | }
296 | }
297 | unload() {
298 | this.loaded = false;
299 | if (isAndroid) {
300 | this.el._nativeView._redrawNativeBackground = this.originalNSFn;
301 | }
302 | }
303 | applyShadow() {
304 | if (!this.shadow && !this.elevation) {
305 | return;
306 | }
307 | if (isAndroid) {
308 | if (android.os.Build.VERSION.SDK_INT < 21) {
309 | return;
310 | }
311 | }
312 | const viewToApplyShadowTo = isIOS ? this.iosShadowWrapper : this.el._nativeView;
313 | if (viewToApplyShadowTo) {
314 | Shadow.apply(viewToApplyShadowTo, {
315 | elevation: this.elevation,
316 | pressedElevation: this.pressedElevation,
317 | shape: this.shape,
318 | bgcolor: this.bgcolor,
319 | cornerRadius: this.cornerRadius,
320 | translationZ: this.translationZ,
321 | pressedTranslationZ: this.pressedTranslationZ,
322 | forcePressAnimation: this.forcePressAnimation,
323 | maskToBounds: this.maskToBounds,
324 | shadowColor: this.shadowColor,
325 | shadowOffset: this.shadowOffset,
326 | shadowOpacity: this.shadowOpacity,
327 | shadowRadius: this.shadowRadius,
328 | rasterize: this.rasterize,
329 | useShadowPath: this.useShadowPath
330 | });
331 | }
332 | }
333 | loadFromAndroidData(data) {
334 | this.elevation = data.elevation || this.elevation;
335 | this.shape = data.shape || this.shape;
336 | this.bgcolor = data.bgcolor || this.bgcolor;
337 | this.cornerRadius = data.cornerRadius || this.cornerRadius;
338 | this.translationZ = data.translationZ || this.translationZ;
339 | this.pressedTranslationZ = data.pressedTranslationZ || this.pressedTranslationZ;
340 | this.forcePressAnimation = data.forcePressAnimation || this.forcePressAnimation;
341 | }
342 | loadFromIOSData(data) {
343 | this.maskToBounds = data.maskToBounds || this.maskToBounds;
344 | this.shadowColor = data.shadowColor || this.shadowColor;
345 | this.shadowOffset = data.shadowOffset || this.shadowOffset;
346 | this.shadowOpacity = data.shadowOpacity || this.shadowOpacity;
347 | this.shadowRadius = data.shadowRadius || this.shadowRadius;
348 | this.rasterize = data.rasterize || this.rasterize;
349 | this.useShadowPath = data.useShadowPath || this.useShadowPath;
350 | }
351 | init() {
352 | if (!this.initialized) {
353 | this.initialized = true;
354 | this.initializeCommonData();
355 | if (isAndroid) {
356 | this.initializeAndroidData();
357 | }
358 | else if (isIOS) {
359 | this.initializeIOSData();
360 | }
361 | if (this.shadow && this.shadow.elevation) {
362 | if (isAndroid) {
363 | this.loadFromAndroidData(this.shadow);
364 | }
365 | else if (isIOS) {
366 | this.loadFromIOSData(this.shadow);
367 | }
368 | }
369 | if (!this.shadow && this.elevation) {
370 | if (isAndroid) {
371 | this.loadFromAndroidData({
372 | elevation: this.elevation,
373 | pressedElevation: this.pressedElevation,
374 | shape: this.shape,
375 | bgcolor: this.bgcolor,
376 | cornerRadius: this.cornerRadius,
377 | translationZ: this.translationZ,
378 | pressedTranslationZ: this.pressedTranslationZ,
379 | forcePressAnimation: this.forcePressAnimation,
380 | });
381 | }
382 | else if (isIOS) {
383 | this.loadFromIOSData({
384 | elevation: this.elevation,
385 | maskToBounds: this.maskToBounds,
386 | shadowColor: this.shadowColor,
387 | shadowOffset: this.shadowOffset,
388 | shadowOpacity: this.shadowOpacity,
389 | shadowRadius: this.shadowRadius,
390 | rasterize: this.rasterize,
391 | useShadowPath: this.useShadowPath
392 | });
393 | }
394 | }
395 | this.bindEvents();
396 | }
397 | }
398 | addIOSWrapper() {
399 | if (isIOS) {
400 | const originalElement = this.el;
401 | const parent = originalElement.parentNode;
402 | const vm = new Vue({
403 | template: '',
404 | }).$mount();
405 | const wrapper = vm.$el;
406 | parent.insertBefore(wrapper, originalElement);
407 | parent.removeChild(originalElement);
408 | wrapper.appendChild(originalElement);
409 | this.iosShadowWrapper = wrapper._nativeView;
410 | }
411 | }
412 | onUpdate(values) {
413 | if (this.loaded && !!values) {
414 | if (typeof values !== 'object' && (typeof values === 'string' || typeof values === 'number')) {
415 | this.shadow = values;
416 | this.elevation = values;
417 | }
418 | if (typeof values === 'object' && values.elevation) {
419 | this.shadow = values;
420 | this.elevation = this.shadow.elevation;
421 | if (isAndroid) {
422 | this.loadFromAndroidData(this.shadow);
423 | }
424 | else if (isIOS) {
425 | this.loadFromIOSData(this.shadow);
426 | }
427 | }
428 | this.applyShadow();
429 | }
430 | }
431 | destroy() {
432 | if (this.initialized) {
433 | this.unload();
434 | this.unbindEvents();
435 | this.initialized = false;
436 | }
437 | }
438 | }
439 | const ShadowDirective = {
440 | bind(el, binding, vnode) {
441 | const shadowDir = new NativeShadowDirective(el, binding);
442 | shadowDir.init();
443 | el.__vShadow = shadowDir;
444 | },
445 | inserted(el, binding, vnode) {
446 | const shadowDir = el.__vShadow;
447 | shadowDir.addIOSWrapper();
448 | },
449 | update(el, { value }, vnode) {
450 | const shadowDir = el.__vShadow;
451 | shadowDir.onUpdate(value);
452 | },
453 | unbind(el, binding, vnode) {
454 | const shadowDir = el.__vShadow;
455 | shadowDir.destroy();
456 | el.__vShadow = null;
457 | },
458 | };
459 |
460 | var Elevation;
461 | (function (Elevation) {
462 | Elevation[Elevation["SWITCH"] = 1] = "SWITCH";
463 | Elevation[Elevation["CARD_RESTING"] = 2] = "CARD_RESTING";
464 | Elevation[Elevation["RAISED_BUTTON_RESTING"] = 2] = "RAISED_BUTTON_RESTING";
465 | Elevation[Elevation["SEARCH_BAR_RESTING"] = 2] = "SEARCH_BAR_RESTING";
466 | Elevation[Elevation["REFRESH_INDICADOR"] = 3] = "REFRESH_INDICADOR";
467 | Elevation[Elevation["SEARCH_BAR_SCROLLED"] = 3] = "SEARCH_BAR_SCROLLED";
468 | Elevation[Elevation["APPBAR"] = 4] = "APPBAR";
469 | Elevation[Elevation["FAB_RESTING"] = 6] = "FAB_RESTING";
470 | Elevation[Elevation["SNACKBAR"] = 6] = "SNACKBAR";
471 | Elevation[Elevation["BOTTOM_NAVIGATION_BAR"] = 8] = "BOTTOM_NAVIGATION_BAR";
472 | Elevation[Elevation["MENU"] = 8] = "MENU";
473 | Elevation[Elevation["CARD_PICKED_UP"] = 8] = "CARD_PICKED_UP";
474 | Elevation[Elevation["RAISED_BUTTON_PRESSED"] = 8] = "RAISED_BUTTON_PRESSED";
475 | Elevation[Elevation["SUBMENU_LEVEL1"] = 9] = "SUBMENU_LEVEL1";
476 | Elevation[Elevation["SUBMENU_LEVEL2"] = 10] = "SUBMENU_LEVEL2";
477 | Elevation[Elevation["SUBMENU_LEVEL3"] = 11] = "SUBMENU_LEVEL3";
478 | Elevation[Elevation["SUBMENU_LEVEL4"] = 12] = "SUBMENU_LEVEL4";
479 | Elevation[Elevation["SUBMENU_LEVEL5"] = 13] = "SUBMENU_LEVEL5";
480 | Elevation[Elevation["FAB_PRESSED"] = 12] = "FAB_PRESSED";
481 | Elevation[Elevation["NAV_DRAWER"] = 16] = "NAV_DRAWER";
482 | Elevation[Elevation["RIGHT_DRAWER"] = 16] = "RIGHT_DRAWER";
483 | Elevation[Elevation["MODAL_BOTTOM_SHEET"] = 16] = "MODAL_BOTTOM_SHEET";
484 | Elevation[Elevation["DIALOG"] = 24] = "DIALOG";
485 | Elevation[Elevation["PICKER"] = 24] = "PICKER";
486 | })(Elevation || (Elevation = {}));
487 |
488 | function install(Vue) {
489 | if (install.installed) {
490 | console.log('not installed');
491 | return;
492 | }
493 | else {
494 | install.installed = true;
495 | Vue.directive('shadow', ShadowDirective);
496 | }
497 | }
498 | class NSVueShadow {
499 | }
500 | (function (install) {
501 | })(install || (install = {}));
502 | NSVueShadow.install = install;
503 | let GlobalVue;
504 | if (typeof window !== "undefined" && typeof window.Vue !== 'undefined') {
505 | GlobalVue = window.Vue;
506 | }
507 | else if (typeof global !== "undefined" && typeof global['Vue'] !== 'undefined') {
508 | GlobalVue = global['Vue'];
509 | }
510 | if (GlobalVue) {
511 | GlobalVue.use(NSVueShadow);
512 | }
513 |
514 | export default NSVueShadow;
515 | export { Elevation, Shadow, ShapeEnum, install };
516 |
--------------------------------------------------------------------------------
/dist/nativescript-vue-shadow.js:
--------------------------------------------------------------------------------
1 | var NativescriptVueshadow=(function(exports,Vue,platform,color,page,weakEventListener){'use strict';Vue=Vue&&Vue.hasOwnProperty('default')?Vue['default']:Vue;(function (ShapeEnum) {
2 | ShapeEnum["RECTANGLE"] = "RECTANGLE";
3 | ShapeEnum["OVAL"] = "OVAL";
4 | ShapeEnum["RING"] = "RING";
5 | ShapeEnum["LINE"] = "LINE";
6 | })(exports.ShapeEnum || (exports.ShapeEnum = {}));let LayeredShadow;
7 | let PlainShadow;
8 | if (platform.isAndroid) {
9 | LayeredShadow = android.graphics.drawable.LayerDrawable.extend({});
10 | PlainShadow = android.graphics.drawable.GradientDrawable.extend({});
11 | }
12 | const classCache = {};
13 | function getAndroidR(rtype, field) {
14 | const className = "android.R$" + rtype;
15 | if (!classCache.hasOwnProperty(className)) {
16 | classCache[className] = {
17 | class: java.lang.Class.forName(className),
18 | fieldCache: {}
19 | };
20 | }
21 | if (!classCache[className].fieldCache.hasOwnProperty(field)) {
22 | classCache[className].fieldCache[field] = +classCache[className].class.getField(field).get(null);
23 | }
24 | return classCache[className].fieldCache[field];
25 | }
26 | class Shadow {
27 | static apply(tnsView, data) {
28 | const LOLLIPOP = 21;
29 | if (tnsView.android &&
30 | android.os.Build.VERSION.SDK_INT >= LOLLIPOP) {
31 | Shadow.applyOnAndroid(tnsView, Shadow.getDefaults(data));
32 | }
33 | else if (tnsView.ios) {
34 | Shadow.applyOnIOS(tnsView, Shadow.getDefaults(data));
35 | }
36 | }
37 | static getDefaults(data) {
38 | return Object.assign({}, data, {
39 | shape: data.shape || Shadow.DEFAULT_SHAPE,
40 | pressedElevation: data.pressedElevation || Shadow.DEFAULT_PRESSED_ELEVATION,
41 | pressedTranslationZ: data.pressedTranslationZ || Shadow.DEFAULT_PRESSED_ELEVATION,
42 | shadowColor: data.shadowColor ||
43 | Shadow.DEFAULT_SHADOW_COLOR,
44 | useShadowPath: (data.useShadowPath !== undefined ? data.useShadowPath : true),
45 | rasterize: (data.rasterize !== undefined ? data.rasterize : false)
46 | });
47 | }
48 | static isShadow(drawable) {
49 | return (drawable instanceof LayeredShadow || drawable instanceof PlainShadow);
50 | }
51 | static applyOnAndroid(tnsView, data) {
52 | const nativeView = tnsView.android;
53 | let shape;
54 | let overrideBackground = true;
55 | let currentBg = nativeView.getBackground();
56 | if (currentBg instanceof android.graphics.drawable.RippleDrawable) {
57 | let rippleBg = currentBg.getDrawable(0);
58 | if (rippleBg instanceof android.graphics.drawable.InsetDrawable) {
59 | overrideBackground = false;
60 | }
61 | else if (Shadow.isShadow(rippleBg)) {
62 | currentBg = rippleBg;
63 | }
64 | }
65 | if (overrideBackground) {
66 | if (Shadow.isShadow(currentBg)) {
67 | currentBg = currentBg instanceof LayeredShadow ?
68 | currentBg.getDrawable(1) : null;
69 | }
70 | const outerRadii = Array.create("float", 8);
71 | if (data.cornerRadius === undefined) {
72 | outerRadii[0] = outerRadii[1] = page.Length.toDevicePixels(tnsView.borderTopLeftRadius, 0);
73 | outerRadii[2] = outerRadii[3] = page.Length.toDevicePixels(tnsView.borderTopRightRadius, 0);
74 | outerRadii[4] = outerRadii[5] = page.Length.toDevicePixels(tnsView.borderBottomRightRadius, 0);
75 | outerRadii[6] = outerRadii[7] = page.Length.toDevicePixels(tnsView.borderBottomLeftRadius, 0);
76 | }
77 | else {
78 | java.util.Arrays.fill(outerRadii, Shadow.androidDipToPx(nativeView, data.cornerRadius));
79 | }
80 | const bgColor = currentBg ?
81 | (currentBg instanceof android.graphics.drawable.ColorDrawable && currentBg.getColor() ?
82 | currentBg.getColor() : android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR)) :
83 | android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR);
84 | let newBg;
85 | if (data.shape !== exports.ShapeEnum.RECTANGLE || data.bgcolor || !currentBg) {
86 | shape = new PlainShadow();
87 | shape.setShape(android.graphics.drawable.GradientDrawable[data.shape]);
88 | shape.setCornerRadii(outerRadii);
89 | shape.setColor(bgColor);
90 | newBg = shape;
91 | }
92 | else {
93 | const r = new android.graphics.drawable.shapes.RoundRectShape(outerRadii, null, null);
94 | shape = new android.graphics.drawable.ShapeDrawable(r);
95 | shape.getPaint().setColor(bgColor);
96 | var arr = Array.create(android.graphics.drawable.Drawable, 2);
97 | arr[0] = shape;
98 | arr[1] = currentBg;
99 | const drawable = new LayeredShadow(arr);
100 | newBg = drawable;
101 | }
102 | nativeView.setBackgroundDrawable(newBg);
103 | }
104 | nativeView.setElevation(Shadow.androidDipToPx(nativeView, data.elevation));
105 | nativeView.setTranslationZ(Shadow.androidDipToPx(nativeView, data.translationZ));
106 | if (nativeView.getStateListAnimator() || data.forcePressAnimation) {
107 | this.overrideDefaultAnimator(nativeView, data);
108 | }
109 | }
110 | static overrideDefaultAnimator(nativeView, data) {
111 | const sla = new android.animation.StateListAnimator();
112 | const ObjectAnimator = android.animation.ObjectAnimator;
113 | const AnimatorSet = android.animation.AnimatorSet;
114 | const shortAnimTime = getAndroidR("integer", "config_shortAnimTime");
115 | const buttonDuration = nativeView.getContext().getResources().getInteger(shortAnimTime) / 2;
116 | const pressedElevation = this.androidDipToPx(nativeView, data.pressedElevation);
117 | const pressedZ = this.androidDipToPx(nativeView, data.pressedTranslationZ);
118 | const elevation = this.androidDipToPx(nativeView, data.elevation);
119 | const z = this.androidDipToPx(nativeView, data.translationZ || 0);
120 | const pressedSet = new AnimatorSet();
121 | const notPressedSet = new AnimatorSet();
122 | const defaultSet = new AnimatorSet();
123 | pressedSet.playTogether(java.util.Arrays.asList([
124 | ObjectAnimator.ofFloat(nativeView, "translationZ", [pressedZ])
125 | .setDuration(buttonDuration),
126 | ObjectAnimator.ofFloat(nativeView, "elevation", [pressedElevation])
127 | .setDuration(0),
128 | ]));
129 | notPressedSet.playTogether(java.util.Arrays.asList([
130 | ObjectAnimator.ofFloat(nativeView, "translationZ", [z])
131 | .setDuration(buttonDuration),
132 | ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
133 | .setDuration(0),
134 | ]));
135 | defaultSet.playTogether(java.util.Arrays.asList([
136 | ObjectAnimator.ofFloat(nativeView, "translationZ", [0]).setDuration(0),
137 | ObjectAnimator.ofFloat(nativeView, "elevation", [0]).setDuration(0),
138 | ]));
139 | sla.addState([getAndroidR("attr", "state_pressed"), getAndroidR("attr", "state_enabled")], pressedSet);
140 | sla.addState([getAndroidR("attr", "state_enabled")], notPressedSet);
141 | sla.addState([], defaultSet);
142 | nativeView.setStateListAnimator(sla);
143 | }
144 | static applyOnIOS(tnsView, data) {
145 | const nativeView = tnsView.ios;
146 | const elevation = parseFloat((data.elevation - 0).toFixed(2));
147 | nativeView.layer.maskToBounds = false;
148 | nativeView.layer.shadowColor = new color.Color(data.shadowColor).ios.CGColor;
149 | nativeView.layer.shadowOffset =
150 | data.shadowOffset ?
151 | CGSizeMake(0, parseFloat(String(data.shadowOffset))) :
152 | CGSizeMake(0, 0.54 * elevation - 0.14);
153 | nativeView.layer.shadowOpacity =
154 | data.shadowOpacity ?
155 | parseFloat(String(data.shadowOpacity)) :
156 | 0.006 * elevation + 0.25;
157 | nativeView.layer.shadowRadius =
158 | data.shadowRadius ?
159 | parseFloat(String(data.shadowRadius)) :
160 | 0.66 * elevation - 0.5;
161 | nativeView.layer.shouldRasterize = data.rasterize;
162 | nativeView.layer.rasterizationScale = platform.screen.mainScreen.scale;
163 | let shadowPath = null;
164 | if (data.useShadowPath) {
165 | shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(nativeView.bounds, nativeView.layer.shadowRadius).cgPath;
166 | }
167 | nativeView.layer.shadowPath = shadowPath;
168 | }
169 | static androidDipToPx(nativeView, dip) {
170 | const metrics = nativeView.getContext().getResources().getDisplayMetrics();
171 | return android.util.TypedValue.applyDimension(android.util.TypedValue.COMPLEX_UNIT_DIP, dip, metrics);
172 | }
173 | }
174 | Shadow.DEFAULT_SHAPE = exports.ShapeEnum.RECTANGLE;
175 | Shadow.DEFAULT_BGCOLOR = '#FFFFFF';
176 | Shadow.DEFAULT_SHADOW_COLOR = '#000000';
177 | Shadow.DEFAULT_PRESSED_ELEVATION = 2;
178 | Shadow.DEFAULT_PRESSED_Z = 4;class NativeShadowDirective {
179 | constructor(el, binding) {
180 | this.loaded = false;
181 | this.initialized = false;
182 | this.eventsBound = false;
183 | this.monkeyPatch = (val) => {
184 | this.previousNSFn.call(this.el._nativeView, val);
185 | this.applyShadow();
186 | };
187 | this.el = el;
188 | if (binding.value && typeof binding.value !== 'object' && (typeof binding.value === 'string' || typeof binding.value === 'number')) {
189 | this.shadow = binding.value;
190 | this.elevation = binding.value;
191 | }
192 | if (binding.value && typeof binding.value === 'object' && binding.value.elevation) {
193 | this.shadow = binding.value;
194 | this.elevation = this.shadow.elevation;
195 | if (platform.isAndroid && (('pressedElevation' in this.shadow) ||
196 | ('shape' in this.shadow) ||
197 | ('bgcolor' in this.shadow) ||
198 | ('cornerRadius' in this.shadow) ||
199 | ('translationZ' in this.shadow) ||
200 | ('pressedTranslationZ' in this.shadow) ||
201 | ('forcePressAnimation' in this.shadow))) {
202 | this.pressedElevation = this.shadow.pressedElevation;
203 | this.shape = this.shadow.shape;
204 | this.bgcolor = this.shadow.bgcolor;
205 | this.cornerRadius = this.shadow.cornerRadius;
206 | this.translationZ = this.shadow.translationZ;
207 | this.pressedTranslationZ = this.shadow.pressedTranslationZ;
208 | this.forcePressAnimation = this.shadow.forcePressAnimation;
209 | }
210 | else if (platform.isIOS && (('maskToBounds' in this.shadow) ||
211 | ('shadowColor' in this.shadow) ||
212 | ('shadowOffset' in this.shadow) ||
213 | ('shadowOpacity' in this.shadow) ||
214 | ('shadowRadius' in this.shadow) ||
215 | ('useShadowPath' in this.shadow) ||
216 | ('rasterize' in this.shadow))) {
217 | this.maskToBounds = this.shadow.maskToBounds;
218 | this.shadowColor = this.shadow.shadowColor;
219 | this.shadowOffset = this.shadow.shadowOffset;
220 | this.shadowOpacity = this.shadow.shadowOpacity;
221 | this.shadowRadius = this.shadow.shadowRadius;
222 | this.useShadowPath = this.shadow.useShadowPath;
223 | this.rasterize = this.shadow.rasterize;
224 | }
225 | }
226 | if (platform.isAndroid) {
227 | if (this.el._nativeView._redrawNativeBackground) {
228 | this.originalNSFn = this.el._nativeView._redrawNativeBackground;
229 | }
230 | }
231 | }
232 | initializeCommonData() {
233 | const tShadow = typeof this.shadow;
234 | if ((tShadow === 'string' || tShadow === 'number') && !this.elevation) {
235 | this.elevation = this.shadow ? parseInt(this.shadow, 10) : 2;
236 | }
237 | const tElevation = typeof this.elevation;
238 | if (tElevation === 'string' || tElevation === 'number') {
239 | this.elevation = this.elevation ? parseInt(this.elevation, 10) : 2;
240 | }
241 | }
242 | initializeAndroidData() {
243 | if (typeof this.cornerRadius === 'string') {
244 | this.cornerRadius = parseInt(this.cornerRadius, 10);
245 | }
246 | if (typeof this.translationZ === 'string') {
247 | this.translationZ = parseInt(this.translationZ, 10);
248 | }
249 | }
250 | initializeIOSData() {
251 | if (typeof this.shadowOffset === 'string') {
252 | this.shadowOffset = parseFloat(this.shadowOffset);
253 | }
254 | if (typeof this.shadowOpacity === 'string') {
255 | this.shadowOpacity = parseFloat(this.shadowOpacity);
256 | }
257 | if (typeof this.shadowRadius === 'string') {
258 | this.shadowRadius = parseFloat(this.shadowRadius);
259 | }
260 | }
261 | bindEvents() {
262 | if (!this.eventsBound) {
263 | weakEventListener.addWeakEventListener(this.el._nativeView, page.View.loadedEvent, this.load, this);
264 | weakEventListener.addWeakEventListener(this.el._nativeView, page.View.unloadedEvent, this.unload, this);
265 | this.eventsBound = true;
266 | if (this.el._nativeView.isLoaded) {
267 | this.load();
268 | }
269 | }
270 | }
271 | unbindEvents() {
272 | if (this.eventsBound) {
273 | weakEventListener.removeWeakEventListener(this.el._nativeView, page.View.loadedEvent, this.load, this);
274 | weakEventListener.removeWeakEventListener(this.el._nativeView, page.View.unloadedEvent, this.unload, this);
275 | this.eventsBound = false;
276 | }
277 | }
278 | load() {
279 | this.loaded = true;
280 | this.applyShadow();
281 | if (platform.isAndroid) {
282 | this.previousNSFn = this.el._nativeView._redrawNativeBackground;
283 | this.el._nativeView._redrawNativeBackground = this.monkeyPatch;
284 | }
285 | }
286 | unload() {
287 | this.loaded = false;
288 | if (platform.isAndroid) {
289 | this.el._nativeView._redrawNativeBackground = this.originalNSFn;
290 | }
291 | }
292 | applyShadow() {
293 | if (!this.shadow && !this.elevation) {
294 | return;
295 | }
296 | if (platform.isAndroid) {
297 | if (android.os.Build.VERSION.SDK_INT < 21) {
298 | return;
299 | }
300 | }
301 | const viewToApplyShadowTo = platform.isIOS ? this.iosShadowWrapper : this.el._nativeView;
302 | if (viewToApplyShadowTo) {
303 | Shadow.apply(viewToApplyShadowTo, {
304 | elevation: this.elevation,
305 | pressedElevation: this.pressedElevation,
306 | shape: this.shape,
307 | bgcolor: this.bgcolor,
308 | cornerRadius: this.cornerRadius,
309 | translationZ: this.translationZ,
310 | pressedTranslationZ: this.pressedTranslationZ,
311 | forcePressAnimation: this.forcePressAnimation,
312 | maskToBounds: this.maskToBounds,
313 | shadowColor: this.shadowColor,
314 | shadowOffset: this.shadowOffset,
315 | shadowOpacity: this.shadowOpacity,
316 | shadowRadius: this.shadowRadius,
317 | rasterize: this.rasterize,
318 | useShadowPath: this.useShadowPath
319 | });
320 | }
321 | }
322 | loadFromAndroidData(data) {
323 | this.elevation = data.elevation || this.elevation;
324 | this.shape = data.shape || this.shape;
325 | this.bgcolor = data.bgcolor || this.bgcolor;
326 | this.cornerRadius = data.cornerRadius || this.cornerRadius;
327 | this.translationZ = data.translationZ || this.translationZ;
328 | this.pressedTranslationZ = data.pressedTranslationZ || this.pressedTranslationZ;
329 | this.forcePressAnimation = data.forcePressAnimation || this.forcePressAnimation;
330 | }
331 | loadFromIOSData(data) {
332 | this.maskToBounds = data.maskToBounds || this.maskToBounds;
333 | this.shadowColor = data.shadowColor || this.shadowColor;
334 | this.shadowOffset = data.shadowOffset || this.shadowOffset;
335 | this.shadowOpacity = data.shadowOpacity || this.shadowOpacity;
336 | this.shadowRadius = data.shadowRadius || this.shadowRadius;
337 | this.rasterize = data.rasterize || this.rasterize;
338 | this.useShadowPath = data.useShadowPath || this.useShadowPath;
339 | }
340 | init() {
341 | if (!this.initialized) {
342 | this.initialized = true;
343 | this.initializeCommonData();
344 | if (platform.isAndroid) {
345 | this.initializeAndroidData();
346 | }
347 | else if (platform.isIOS) {
348 | this.initializeIOSData();
349 | }
350 | if (this.shadow && this.shadow.elevation) {
351 | if (platform.isAndroid) {
352 | this.loadFromAndroidData(this.shadow);
353 | }
354 | else if (platform.isIOS) {
355 | this.loadFromIOSData(this.shadow);
356 | }
357 | }
358 | if (!this.shadow && this.elevation) {
359 | if (platform.isAndroid) {
360 | this.loadFromAndroidData({
361 | elevation: this.elevation,
362 | pressedElevation: this.pressedElevation,
363 | shape: this.shape,
364 | bgcolor: this.bgcolor,
365 | cornerRadius: this.cornerRadius,
366 | translationZ: this.translationZ,
367 | pressedTranslationZ: this.pressedTranslationZ,
368 | forcePressAnimation: this.forcePressAnimation,
369 | });
370 | }
371 | else if (platform.isIOS) {
372 | this.loadFromIOSData({
373 | elevation: this.elevation,
374 | maskToBounds: this.maskToBounds,
375 | shadowColor: this.shadowColor,
376 | shadowOffset: this.shadowOffset,
377 | shadowOpacity: this.shadowOpacity,
378 | shadowRadius: this.shadowRadius,
379 | rasterize: this.rasterize,
380 | useShadowPath: this.useShadowPath
381 | });
382 | }
383 | }
384 | this.bindEvents();
385 | }
386 | }
387 | addIOSWrapper() {
388 | if (platform.isIOS) {
389 | const originalElement = this.el;
390 | const parent = originalElement.parentNode;
391 | const vm = new Vue({
392 | template: '',
393 | }).$mount();
394 | const wrapper = vm.$el;
395 | parent.insertBefore(wrapper, originalElement);
396 | parent.removeChild(originalElement);
397 | wrapper.appendChild(originalElement);
398 | this.iosShadowWrapper = wrapper._nativeView;
399 | }
400 | }
401 | onUpdate(values) {
402 | if (this.loaded && !!values) {
403 | if (typeof values !== 'object' && (typeof values === 'string' || typeof values === 'number')) {
404 | this.shadow = values;
405 | this.elevation = values;
406 | }
407 | if (typeof values === 'object' && values.elevation) {
408 | this.shadow = values;
409 | this.elevation = this.shadow.elevation;
410 | if (platform.isAndroid) {
411 | this.loadFromAndroidData(this.shadow);
412 | }
413 | else if (platform.isIOS) {
414 | this.loadFromIOSData(this.shadow);
415 | }
416 | }
417 | this.applyShadow();
418 | }
419 | }
420 | destroy() {
421 | if (this.initialized) {
422 | this.unload();
423 | this.unbindEvents();
424 | this.initialized = false;
425 | }
426 | }
427 | }
428 | const ShadowDirective = {
429 | bind(el, binding, vnode) {
430 | const shadowDir = new NativeShadowDirective(el, binding);
431 | shadowDir.init();
432 | el.__vShadow = shadowDir;
433 | },
434 | inserted(el, binding, vnode) {
435 | const shadowDir = el.__vShadow;
436 | shadowDir.addIOSWrapper();
437 | },
438 | update(el, { value }, vnode) {
439 | const shadowDir = el.__vShadow;
440 | shadowDir.onUpdate(value);
441 | },
442 | unbind(el, binding, vnode) {
443 | const shadowDir = el.__vShadow;
444 | shadowDir.destroy();
445 | el.__vShadow = null;
446 | },
447 | };(function (Elevation) {
448 | Elevation[Elevation["SWITCH"] = 1] = "SWITCH";
449 | Elevation[Elevation["CARD_RESTING"] = 2] = "CARD_RESTING";
450 | Elevation[Elevation["RAISED_BUTTON_RESTING"] = 2] = "RAISED_BUTTON_RESTING";
451 | Elevation[Elevation["SEARCH_BAR_RESTING"] = 2] = "SEARCH_BAR_RESTING";
452 | Elevation[Elevation["REFRESH_INDICADOR"] = 3] = "REFRESH_INDICADOR";
453 | Elevation[Elevation["SEARCH_BAR_SCROLLED"] = 3] = "SEARCH_BAR_SCROLLED";
454 | Elevation[Elevation["APPBAR"] = 4] = "APPBAR";
455 | Elevation[Elevation["FAB_RESTING"] = 6] = "FAB_RESTING";
456 | Elevation[Elevation["SNACKBAR"] = 6] = "SNACKBAR";
457 | Elevation[Elevation["BOTTOM_NAVIGATION_BAR"] = 8] = "BOTTOM_NAVIGATION_BAR";
458 | Elevation[Elevation["MENU"] = 8] = "MENU";
459 | Elevation[Elevation["CARD_PICKED_UP"] = 8] = "CARD_PICKED_UP";
460 | Elevation[Elevation["RAISED_BUTTON_PRESSED"] = 8] = "RAISED_BUTTON_PRESSED";
461 | Elevation[Elevation["SUBMENU_LEVEL1"] = 9] = "SUBMENU_LEVEL1";
462 | Elevation[Elevation["SUBMENU_LEVEL2"] = 10] = "SUBMENU_LEVEL2";
463 | Elevation[Elevation["SUBMENU_LEVEL3"] = 11] = "SUBMENU_LEVEL3";
464 | Elevation[Elevation["SUBMENU_LEVEL4"] = 12] = "SUBMENU_LEVEL4";
465 | Elevation[Elevation["SUBMENU_LEVEL5"] = 13] = "SUBMENU_LEVEL5";
466 | Elevation[Elevation["FAB_PRESSED"] = 12] = "FAB_PRESSED";
467 | Elevation[Elevation["NAV_DRAWER"] = 16] = "NAV_DRAWER";
468 | Elevation[Elevation["RIGHT_DRAWER"] = 16] = "RIGHT_DRAWER";
469 | Elevation[Elevation["MODAL_BOTTOM_SHEET"] = 16] = "MODAL_BOTTOM_SHEET";
470 | Elevation[Elevation["DIALOG"] = 24] = "DIALOG";
471 | Elevation[Elevation["PICKER"] = 24] = "PICKER";
472 | })(exports.Elevation || (exports.Elevation = {}));function install(Vue) {
473 | if (install.installed) {
474 | console.log('not installed');
475 | return;
476 | }
477 | else {
478 | install.installed = true;
479 | Vue.directive('shadow', ShadowDirective);
480 | }
481 | }
482 | class NSVueShadow {
483 | }
484 | (function (install) {
485 | })(install || (install = {}));
486 | NSVueShadow.install = install;
487 | let GlobalVue;
488 | if (typeof window !== "undefined" && typeof window.Vue !== 'undefined') {
489 | GlobalVue = window.Vue;
490 | }
491 | else if (typeof global !== "undefined" && typeof global['Vue'] !== 'undefined') {
492 | GlobalVue = global['Vue'];
493 | }
494 | if (GlobalVue) {
495 | GlobalVue.use(NSVueShadow);
496 | }exports.Shadow=Shadow;exports.default=NSVueShadow;exports.install=install;return exports;}({},vue,platform,color,page,weakEventListener));
--------------------------------------------------------------------------------
/dist/nativescript-vue-shadow.umd.js:
--------------------------------------------------------------------------------
1 | (function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports,require('nativescript-vue'),require('tns-core-modules/platform'),require('tns-core-modules/color'),require('tns-core-modules/ui/page/page'),require('tns-core-modules/ui/core/weak-event-listener')):typeof define==='function'&&define.amd?define(['exports','nativescript-vue','tns-core-modules/platform','tns-core-modules/color','tns-core-modules/ui/page/page','tns-core-modules/ui/core/weak-event-listener'],f):(g=g||self,f(g.NativescriptVueshadow={},g.vue,g.platform,g.color,g.page,g.weakEventListener));}(this,function(exports, Vue, platform, color, page, weakEventListener){'use strict';Vue=Vue&&Vue.hasOwnProperty('default')?Vue['default']:Vue;(function (ShapeEnum) {
2 | ShapeEnum["RECTANGLE"] = "RECTANGLE";
3 | ShapeEnum["OVAL"] = "OVAL";
4 | ShapeEnum["RING"] = "RING";
5 | ShapeEnum["LINE"] = "LINE";
6 | })(exports.ShapeEnum || (exports.ShapeEnum = {}));let LayeredShadow;
7 | let PlainShadow;
8 | if (platform.isAndroid) {
9 | LayeredShadow = android.graphics.drawable.LayerDrawable.extend({});
10 | PlainShadow = android.graphics.drawable.GradientDrawable.extend({});
11 | }
12 | const classCache = {};
13 | function getAndroidR(rtype, field) {
14 | const className = "android.R$" + rtype;
15 | if (!classCache.hasOwnProperty(className)) {
16 | classCache[className] = {
17 | class: java.lang.Class.forName(className),
18 | fieldCache: {}
19 | };
20 | }
21 | if (!classCache[className].fieldCache.hasOwnProperty(field)) {
22 | classCache[className].fieldCache[field] = +classCache[className].class.getField(field).get(null);
23 | }
24 | return classCache[className].fieldCache[field];
25 | }
26 | class Shadow {
27 | static apply(tnsView, data) {
28 | const LOLLIPOP = 21;
29 | if (tnsView.android &&
30 | android.os.Build.VERSION.SDK_INT >= LOLLIPOP) {
31 | Shadow.applyOnAndroid(tnsView, Shadow.getDefaults(data));
32 | }
33 | else if (tnsView.ios) {
34 | Shadow.applyOnIOS(tnsView, Shadow.getDefaults(data));
35 | }
36 | }
37 | static getDefaults(data) {
38 | return Object.assign({}, data, {
39 | shape: data.shape || Shadow.DEFAULT_SHAPE,
40 | pressedElevation: data.pressedElevation || Shadow.DEFAULT_PRESSED_ELEVATION,
41 | pressedTranslationZ: data.pressedTranslationZ || Shadow.DEFAULT_PRESSED_ELEVATION,
42 | shadowColor: data.shadowColor ||
43 | Shadow.DEFAULT_SHADOW_COLOR,
44 | useShadowPath: (data.useShadowPath !== undefined ? data.useShadowPath : true),
45 | rasterize: (data.rasterize !== undefined ? data.rasterize : false)
46 | });
47 | }
48 | static isShadow(drawable) {
49 | return (drawable instanceof LayeredShadow || drawable instanceof PlainShadow);
50 | }
51 | static applyOnAndroid(tnsView, data) {
52 | const nativeView = tnsView.android;
53 | let shape;
54 | let overrideBackground = true;
55 | let currentBg = nativeView.getBackground();
56 | if (currentBg instanceof android.graphics.drawable.RippleDrawable) {
57 | let rippleBg = currentBg.getDrawable(0);
58 | if (rippleBg instanceof android.graphics.drawable.InsetDrawable) {
59 | overrideBackground = false;
60 | }
61 | else if (Shadow.isShadow(rippleBg)) {
62 | currentBg = rippleBg;
63 | }
64 | }
65 | if (overrideBackground) {
66 | if (Shadow.isShadow(currentBg)) {
67 | currentBg = currentBg instanceof LayeredShadow ?
68 | currentBg.getDrawable(1) : null;
69 | }
70 | const outerRadii = Array.create("float", 8);
71 | if (data.cornerRadius === undefined) {
72 | outerRadii[0] = outerRadii[1] = page.Length.toDevicePixels(tnsView.borderTopLeftRadius, 0);
73 | outerRadii[2] = outerRadii[3] = page.Length.toDevicePixels(tnsView.borderTopRightRadius, 0);
74 | outerRadii[4] = outerRadii[5] = page.Length.toDevicePixels(tnsView.borderBottomRightRadius, 0);
75 | outerRadii[6] = outerRadii[7] = page.Length.toDevicePixels(tnsView.borderBottomLeftRadius, 0);
76 | }
77 | else {
78 | java.util.Arrays.fill(outerRadii, Shadow.androidDipToPx(nativeView, data.cornerRadius));
79 | }
80 | const bgColor = currentBg ?
81 | (currentBg instanceof android.graphics.drawable.ColorDrawable && currentBg.getColor() ?
82 | currentBg.getColor() : android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR)) :
83 | android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR);
84 | let newBg;
85 | if (data.shape !== exports.ShapeEnum.RECTANGLE || data.bgcolor || !currentBg) {
86 | shape = new PlainShadow();
87 | shape.setShape(android.graphics.drawable.GradientDrawable[data.shape]);
88 | shape.setCornerRadii(outerRadii);
89 | shape.setColor(bgColor);
90 | newBg = shape;
91 | }
92 | else {
93 | const r = new android.graphics.drawable.shapes.RoundRectShape(outerRadii, null, null);
94 | shape = new android.graphics.drawable.ShapeDrawable(r);
95 | shape.getPaint().setColor(bgColor);
96 | var arr = Array.create(android.graphics.drawable.Drawable, 2);
97 | arr[0] = shape;
98 | arr[1] = currentBg;
99 | const drawable = new LayeredShadow(arr);
100 | newBg = drawable;
101 | }
102 | nativeView.setBackgroundDrawable(newBg);
103 | }
104 | nativeView.setElevation(Shadow.androidDipToPx(nativeView, data.elevation));
105 | nativeView.setTranslationZ(Shadow.androidDipToPx(nativeView, data.translationZ));
106 | if (nativeView.getStateListAnimator() || data.forcePressAnimation) {
107 | this.overrideDefaultAnimator(nativeView, data);
108 | }
109 | }
110 | static overrideDefaultAnimator(nativeView, data) {
111 | const sla = new android.animation.StateListAnimator();
112 | const ObjectAnimator = android.animation.ObjectAnimator;
113 | const AnimatorSet = android.animation.AnimatorSet;
114 | const shortAnimTime = getAndroidR("integer", "config_shortAnimTime");
115 | const buttonDuration = nativeView.getContext().getResources().getInteger(shortAnimTime) / 2;
116 | const pressedElevation = this.androidDipToPx(nativeView, data.pressedElevation);
117 | const pressedZ = this.androidDipToPx(nativeView, data.pressedTranslationZ);
118 | const elevation = this.androidDipToPx(nativeView, data.elevation);
119 | const z = this.androidDipToPx(nativeView, data.translationZ || 0);
120 | const pressedSet = new AnimatorSet();
121 | const notPressedSet = new AnimatorSet();
122 | const defaultSet = new AnimatorSet();
123 | pressedSet.playTogether(java.util.Arrays.asList([
124 | ObjectAnimator.ofFloat(nativeView, "translationZ", [pressedZ])
125 | .setDuration(buttonDuration),
126 | ObjectAnimator.ofFloat(nativeView, "elevation", [pressedElevation])
127 | .setDuration(0),
128 | ]));
129 | notPressedSet.playTogether(java.util.Arrays.asList([
130 | ObjectAnimator.ofFloat(nativeView, "translationZ", [z])
131 | .setDuration(buttonDuration),
132 | ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
133 | .setDuration(0),
134 | ]));
135 | defaultSet.playTogether(java.util.Arrays.asList([
136 | ObjectAnimator.ofFloat(nativeView, "translationZ", [0]).setDuration(0),
137 | ObjectAnimator.ofFloat(nativeView, "elevation", [0]).setDuration(0),
138 | ]));
139 | sla.addState([getAndroidR("attr", "state_pressed"), getAndroidR("attr", "state_enabled")], pressedSet);
140 | sla.addState([getAndroidR("attr", "state_enabled")], notPressedSet);
141 | sla.addState([], defaultSet);
142 | nativeView.setStateListAnimator(sla);
143 | }
144 | static applyOnIOS(tnsView, data) {
145 | const nativeView = tnsView.ios;
146 | const elevation = parseFloat((data.elevation - 0).toFixed(2));
147 | nativeView.layer.maskToBounds = false;
148 | nativeView.layer.shadowColor = new color.Color(data.shadowColor).ios.CGColor;
149 | nativeView.layer.shadowOffset =
150 | data.shadowOffset ?
151 | CGSizeMake(0, parseFloat(String(data.shadowOffset))) :
152 | CGSizeMake(0, 0.54 * elevation - 0.14);
153 | nativeView.layer.shadowOpacity =
154 | data.shadowOpacity ?
155 | parseFloat(String(data.shadowOpacity)) :
156 | 0.006 * elevation + 0.25;
157 | nativeView.layer.shadowRadius =
158 | data.shadowRadius ?
159 | parseFloat(String(data.shadowRadius)) :
160 | 0.66 * elevation - 0.5;
161 | nativeView.layer.shouldRasterize = data.rasterize;
162 | nativeView.layer.rasterizationScale = platform.screen.mainScreen.scale;
163 | let shadowPath = null;
164 | if (data.useShadowPath) {
165 | shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(nativeView.bounds, nativeView.layer.shadowRadius).cgPath;
166 | }
167 | nativeView.layer.shadowPath = shadowPath;
168 | }
169 | static androidDipToPx(nativeView, dip) {
170 | const metrics = nativeView.getContext().getResources().getDisplayMetrics();
171 | return android.util.TypedValue.applyDimension(android.util.TypedValue.COMPLEX_UNIT_DIP, dip, metrics);
172 | }
173 | }
174 | Shadow.DEFAULT_SHAPE = exports.ShapeEnum.RECTANGLE;
175 | Shadow.DEFAULT_BGCOLOR = '#FFFFFF';
176 | Shadow.DEFAULT_SHADOW_COLOR = '#000000';
177 | Shadow.DEFAULT_PRESSED_ELEVATION = 2;
178 | Shadow.DEFAULT_PRESSED_Z = 4;class NativeShadowDirective {
179 | constructor(el, binding) {
180 | this.loaded = false;
181 | this.initialized = false;
182 | this.eventsBound = false;
183 | this.monkeyPatch = (val) => {
184 | this.previousNSFn.call(this.el._nativeView, val);
185 | this.applyShadow();
186 | };
187 | this.el = el;
188 | if (binding.value && typeof binding.value !== 'object' && (typeof binding.value === 'string' || typeof binding.value === 'number')) {
189 | this.shadow = binding.value;
190 | this.elevation = binding.value;
191 | }
192 | if (binding.value && typeof binding.value === 'object' && binding.value.elevation) {
193 | this.shadow = binding.value;
194 | this.elevation = this.shadow.elevation;
195 | if (platform.isAndroid && (('pressedElevation' in this.shadow) ||
196 | ('shape' in this.shadow) ||
197 | ('bgcolor' in this.shadow) ||
198 | ('cornerRadius' in this.shadow) ||
199 | ('translationZ' in this.shadow) ||
200 | ('pressedTranslationZ' in this.shadow) ||
201 | ('forcePressAnimation' in this.shadow))) {
202 | this.pressedElevation = this.shadow.pressedElevation;
203 | this.shape = this.shadow.shape;
204 | this.bgcolor = this.shadow.bgcolor;
205 | this.cornerRadius = this.shadow.cornerRadius;
206 | this.translationZ = this.shadow.translationZ;
207 | this.pressedTranslationZ = this.shadow.pressedTranslationZ;
208 | this.forcePressAnimation = this.shadow.forcePressAnimation;
209 | }
210 | else if (platform.isIOS && (('maskToBounds' in this.shadow) ||
211 | ('shadowColor' in this.shadow) ||
212 | ('shadowOffset' in this.shadow) ||
213 | ('shadowOpacity' in this.shadow) ||
214 | ('shadowRadius' in this.shadow) ||
215 | ('useShadowPath' in this.shadow) ||
216 | ('rasterize' in this.shadow))) {
217 | this.maskToBounds = this.shadow.maskToBounds;
218 | this.shadowColor = this.shadow.shadowColor;
219 | this.shadowOffset = this.shadow.shadowOffset;
220 | this.shadowOpacity = this.shadow.shadowOpacity;
221 | this.shadowRadius = this.shadow.shadowRadius;
222 | this.useShadowPath = this.shadow.useShadowPath;
223 | this.rasterize = this.shadow.rasterize;
224 | }
225 | }
226 | if (platform.isAndroid) {
227 | if (this.el._nativeView._redrawNativeBackground) {
228 | this.originalNSFn = this.el._nativeView._redrawNativeBackground;
229 | }
230 | }
231 | }
232 | initializeCommonData() {
233 | const tShadow = typeof this.shadow;
234 | if ((tShadow === 'string' || tShadow === 'number') && !this.elevation) {
235 | this.elevation = this.shadow ? parseInt(this.shadow, 10) : 2;
236 | }
237 | const tElevation = typeof this.elevation;
238 | if (tElevation === 'string' || tElevation === 'number') {
239 | this.elevation = this.elevation ? parseInt(this.elevation, 10) : 2;
240 | }
241 | }
242 | initializeAndroidData() {
243 | if (typeof this.cornerRadius === 'string') {
244 | this.cornerRadius = parseInt(this.cornerRadius, 10);
245 | }
246 | if (typeof this.translationZ === 'string') {
247 | this.translationZ = parseInt(this.translationZ, 10);
248 | }
249 | }
250 | initializeIOSData() {
251 | if (typeof this.shadowOffset === 'string') {
252 | this.shadowOffset = parseFloat(this.shadowOffset);
253 | }
254 | if (typeof this.shadowOpacity === 'string') {
255 | this.shadowOpacity = parseFloat(this.shadowOpacity);
256 | }
257 | if (typeof this.shadowRadius === 'string') {
258 | this.shadowRadius = parseFloat(this.shadowRadius);
259 | }
260 | }
261 | bindEvents() {
262 | if (!this.eventsBound) {
263 | weakEventListener.addWeakEventListener(this.el._nativeView, page.View.loadedEvent, this.load, this);
264 | weakEventListener.addWeakEventListener(this.el._nativeView, page.View.unloadedEvent, this.unload, this);
265 | this.eventsBound = true;
266 | if (this.el._nativeView.isLoaded) {
267 | this.load();
268 | }
269 | }
270 | }
271 | unbindEvents() {
272 | if (this.eventsBound) {
273 | weakEventListener.removeWeakEventListener(this.el._nativeView, page.View.loadedEvent, this.load, this);
274 | weakEventListener.removeWeakEventListener(this.el._nativeView, page.View.unloadedEvent, this.unload, this);
275 | this.eventsBound = false;
276 | }
277 | }
278 | load() {
279 | this.loaded = true;
280 | this.applyShadow();
281 | if (platform.isAndroid) {
282 | this.previousNSFn = this.el._nativeView._redrawNativeBackground;
283 | this.el._nativeView._redrawNativeBackground = this.monkeyPatch;
284 | }
285 | }
286 | unload() {
287 | this.loaded = false;
288 | if (platform.isAndroid) {
289 | this.el._nativeView._redrawNativeBackground = this.originalNSFn;
290 | }
291 | }
292 | applyShadow() {
293 | if (!this.shadow && !this.elevation) {
294 | return;
295 | }
296 | if (platform.isAndroid) {
297 | if (android.os.Build.VERSION.SDK_INT < 21) {
298 | return;
299 | }
300 | }
301 | const viewToApplyShadowTo = platform.isIOS ? this.iosShadowWrapper : this.el._nativeView;
302 | if (viewToApplyShadowTo) {
303 | Shadow.apply(viewToApplyShadowTo, {
304 | elevation: this.elevation,
305 | pressedElevation: this.pressedElevation,
306 | shape: this.shape,
307 | bgcolor: this.bgcolor,
308 | cornerRadius: this.cornerRadius,
309 | translationZ: this.translationZ,
310 | pressedTranslationZ: this.pressedTranslationZ,
311 | forcePressAnimation: this.forcePressAnimation,
312 | maskToBounds: this.maskToBounds,
313 | shadowColor: this.shadowColor,
314 | shadowOffset: this.shadowOffset,
315 | shadowOpacity: this.shadowOpacity,
316 | shadowRadius: this.shadowRadius,
317 | rasterize: this.rasterize,
318 | useShadowPath: this.useShadowPath
319 | });
320 | }
321 | }
322 | loadFromAndroidData(data) {
323 | this.elevation = data.elevation || this.elevation;
324 | this.shape = data.shape || this.shape;
325 | this.bgcolor = data.bgcolor || this.bgcolor;
326 | this.cornerRadius = data.cornerRadius || this.cornerRadius;
327 | this.translationZ = data.translationZ || this.translationZ;
328 | this.pressedTranslationZ = data.pressedTranslationZ || this.pressedTranslationZ;
329 | this.forcePressAnimation = data.forcePressAnimation || this.forcePressAnimation;
330 | }
331 | loadFromIOSData(data) {
332 | this.maskToBounds = data.maskToBounds || this.maskToBounds;
333 | this.shadowColor = data.shadowColor || this.shadowColor;
334 | this.shadowOffset = data.shadowOffset || this.shadowOffset;
335 | this.shadowOpacity = data.shadowOpacity || this.shadowOpacity;
336 | this.shadowRadius = data.shadowRadius || this.shadowRadius;
337 | this.rasterize = data.rasterize || this.rasterize;
338 | this.useShadowPath = data.useShadowPath || this.useShadowPath;
339 | }
340 | init() {
341 | if (!this.initialized) {
342 | this.initialized = true;
343 | this.initializeCommonData();
344 | if (platform.isAndroid) {
345 | this.initializeAndroidData();
346 | }
347 | else if (platform.isIOS) {
348 | this.initializeIOSData();
349 | }
350 | if (this.shadow && this.shadow.elevation) {
351 | if (platform.isAndroid) {
352 | this.loadFromAndroidData(this.shadow);
353 | }
354 | else if (platform.isIOS) {
355 | this.loadFromIOSData(this.shadow);
356 | }
357 | }
358 | if (!this.shadow && this.elevation) {
359 | if (platform.isAndroid) {
360 | this.loadFromAndroidData({
361 | elevation: this.elevation,
362 | pressedElevation: this.pressedElevation,
363 | shape: this.shape,
364 | bgcolor: this.bgcolor,
365 | cornerRadius: this.cornerRadius,
366 | translationZ: this.translationZ,
367 | pressedTranslationZ: this.pressedTranslationZ,
368 | forcePressAnimation: this.forcePressAnimation,
369 | });
370 | }
371 | else if (platform.isIOS) {
372 | this.loadFromIOSData({
373 | elevation: this.elevation,
374 | maskToBounds: this.maskToBounds,
375 | shadowColor: this.shadowColor,
376 | shadowOffset: this.shadowOffset,
377 | shadowOpacity: this.shadowOpacity,
378 | shadowRadius: this.shadowRadius,
379 | rasterize: this.rasterize,
380 | useShadowPath: this.useShadowPath
381 | });
382 | }
383 | }
384 | this.bindEvents();
385 | }
386 | }
387 | addIOSWrapper() {
388 | if (platform.isIOS) {
389 | const originalElement = this.el;
390 | const parent = originalElement.parentNode;
391 | const vm = new Vue({
392 | template: '',
393 | }).$mount();
394 | const wrapper = vm.$el;
395 | parent.insertBefore(wrapper, originalElement);
396 | parent.removeChild(originalElement);
397 | wrapper.appendChild(originalElement);
398 | this.iosShadowWrapper = wrapper._nativeView;
399 | }
400 | }
401 | onUpdate(values) {
402 | if (this.loaded && !!values) {
403 | if (typeof values !== 'object' && (typeof values === 'string' || typeof values === 'number')) {
404 | this.shadow = values;
405 | this.elevation = values;
406 | }
407 | if (typeof values === 'object' && values.elevation) {
408 | this.shadow = values;
409 | this.elevation = this.shadow.elevation;
410 | if (platform.isAndroid) {
411 | this.loadFromAndroidData(this.shadow);
412 | }
413 | else if (platform.isIOS) {
414 | this.loadFromIOSData(this.shadow);
415 | }
416 | }
417 | this.applyShadow();
418 | }
419 | }
420 | destroy() {
421 | if (this.initialized) {
422 | this.unload();
423 | this.unbindEvents();
424 | this.initialized = false;
425 | }
426 | }
427 | }
428 | const ShadowDirective = {
429 | bind(el, binding, vnode) {
430 | const shadowDir = new NativeShadowDirective(el, binding);
431 | shadowDir.init();
432 | el.__vShadow = shadowDir;
433 | },
434 | inserted(el, binding, vnode) {
435 | const shadowDir = el.__vShadow;
436 | shadowDir.addIOSWrapper();
437 | },
438 | update(el, { value }, vnode) {
439 | const shadowDir = el.__vShadow;
440 | shadowDir.onUpdate(value);
441 | },
442 | unbind(el, binding, vnode) {
443 | const shadowDir = el.__vShadow;
444 | shadowDir.destroy();
445 | el.__vShadow = null;
446 | },
447 | };(function (Elevation) {
448 | Elevation[Elevation["SWITCH"] = 1] = "SWITCH";
449 | Elevation[Elevation["CARD_RESTING"] = 2] = "CARD_RESTING";
450 | Elevation[Elevation["RAISED_BUTTON_RESTING"] = 2] = "RAISED_BUTTON_RESTING";
451 | Elevation[Elevation["SEARCH_BAR_RESTING"] = 2] = "SEARCH_BAR_RESTING";
452 | Elevation[Elevation["REFRESH_INDICADOR"] = 3] = "REFRESH_INDICADOR";
453 | Elevation[Elevation["SEARCH_BAR_SCROLLED"] = 3] = "SEARCH_BAR_SCROLLED";
454 | Elevation[Elevation["APPBAR"] = 4] = "APPBAR";
455 | Elevation[Elevation["FAB_RESTING"] = 6] = "FAB_RESTING";
456 | Elevation[Elevation["SNACKBAR"] = 6] = "SNACKBAR";
457 | Elevation[Elevation["BOTTOM_NAVIGATION_BAR"] = 8] = "BOTTOM_NAVIGATION_BAR";
458 | Elevation[Elevation["MENU"] = 8] = "MENU";
459 | Elevation[Elevation["CARD_PICKED_UP"] = 8] = "CARD_PICKED_UP";
460 | Elevation[Elevation["RAISED_BUTTON_PRESSED"] = 8] = "RAISED_BUTTON_PRESSED";
461 | Elevation[Elevation["SUBMENU_LEVEL1"] = 9] = "SUBMENU_LEVEL1";
462 | Elevation[Elevation["SUBMENU_LEVEL2"] = 10] = "SUBMENU_LEVEL2";
463 | Elevation[Elevation["SUBMENU_LEVEL3"] = 11] = "SUBMENU_LEVEL3";
464 | Elevation[Elevation["SUBMENU_LEVEL4"] = 12] = "SUBMENU_LEVEL4";
465 | Elevation[Elevation["SUBMENU_LEVEL5"] = 13] = "SUBMENU_LEVEL5";
466 | Elevation[Elevation["FAB_PRESSED"] = 12] = "FAB_PRESSED";
467 | Elevation[Elevation["NAV_DRAWER"] = 16] = "NAV_DRAWER";
468 | Elevation[Elevation["RIGHT_DRAWER"] = 16] = "RIGHT_DRAWER";
469 | Elevation[Elevation["MODAL_BOTTOM_SHEET"] = 16] = "MODAL_BOTTOM_SHEET";
470 | Elevation[Elevation["DIALOG"] = 24] = "DIALOG";
471 | Elevation[Elevation["PICKER"] = 24] = "PICKER";
472 | })(exports.Elevation || (exports.Elevation = {}));function install(Vue) {
473 | if (install.installed) {
474 | console.log('not installed');
475 | return;
476 | }
477 | else {
478 | install.installed = true;
479 | Vue.directive('shadow', ShadowDirective);
480 | }
481 | }
482 | class NSVueShadow {
483 | }
484 | (function (install) {
485 | })(install || (install = {}));
486 | NSVueShadow.install = install;
487 | let GlobalVue;
488 | if (typeof window !== "undefined" && typeof window.Vue !== 'undefined') {
489 | GlobalVue = window.Vue;
490 | }
491 | else if (typeof global !== "undefined" && typeof global['Vue'] !== 'undefined') {
492 | GlobalVue = global['Vue'];
493 | }
494 | if (GlobalVue) {
495 | GlobalVue.use(NSVueShadow);
496 | }exports.Shadow=Shadow;exports.default=NSVueShadow;exports.install=install;Object.defineProperty(exports,'__esModule',{value:true});}));
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleFileExtensions: ["js", "jsx", "json", "vue", "ts", "tsx"],
3 | transform: {
4 | "^.+\\.vue$": "vue-jest",
5 | ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$":
6 | "jest-transform-stub",
7 | "^.+\\.tsx?$": "ts-jest"
8 | },
9 | transformIgnorePatterns: ["/node_modules/"],
10 | moduleNameMapper: {
11 | "^@/(.*)$": "/src/$1"
12 | },
13 | snapshotSerializers: ["jest-serializer-vue"],
14 | testMatch: [
15 | "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
16 | ],
17 | testURL: "http://localhost/",
18 | globals: {
19 | "ts-jest": {
20 | babelConfig: true
21 | }
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nativescript-vue-shadow",
3 | "version": "0.1.0",
4 | "description": "Nativescript-Vue Shadow Plugin",
5 | "main": "dist/nativescript-vue-shadow.umd.js",
6 | "module": "dist/nativescript-vue-shadow.esm.js",
7 | "unpkg": "dist/nativescript-vue-shadow.js",
8 | "files": [
9 | "dist/*",
10 | "src/*",
11 | "types/*",
12 | "LICENSE"
13 | ],
14 | "typings": "types/index.d.ts",
15 | "scripts": {
16 | "build:dev": "cross-env NODE_ENV=development rollup --config build/rollup.config.js",
17 | "build": "cross-env NODE_ENV=production rollup --config build/rollup.config.js",
18 | "build:umd": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format umd",
19 | "build:es": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format es",
20 | "build:unpkg": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format iife",
21 | "test": "echo \"Error: no test specified\"",
22 | "clean": "rimraf dist/*",
23 | "preversion": "npm run clean && npm test",
24 | "version": "npm run build && git add -A",
25 | "postversion": "git push --tags origin master",
26 | "prep:major": "npm version major -m \"build %s\"",
27 | "prep:minor": "npm version minor -m \"build %s\"",
28 | "prep:patch": "npm version patch -m \"build %s\""
29 | },
30 | "repository": {
31 | "type": "git",
32 | "url": "git+https://github.com/jawa-the-hutt/nativescript-vue-shadow.git"
33 | },
34 | "keywords": [
35 | "vue",
36 | "nativescript",
37 | "typescript",
38 | "web",
39 | "code share",
40 | "shadow"
41 | ],
42 | "author": "Gary Gambill",
43 | "license": "MIT",
44 | "bugs": {
45 | "url": "https://github.com/jawa-the-hutt/nativescript-vue-shadow/issues"
46 | },
47 | "homepage": "https://github.com/jawa-the-hutt/nativescript-vue-shadow#readme",
48 | "dependencies": {
49 | "nativescript-theme-core": "~1.0.4"
50 | },
51 | "devDependencies": {
52 | "@babel/core": "^7.4.3",
53 | "@babel/plugin-syntax-dynamic-import": "^7.2.0",
54 | "@babel/preset-env": "^7.4.3",
55 | "@babel/preset-es2015": "^7.0.0-beta.53",
56 | "@types/jest": "^24.0.11",
57 | "@types/node": "^11.13.4",
58 | "@typescript-eslint/eslint-plugin": "^1.6.0",
59 | "@typescript-eslint/parser": "^1.6.0",
60 | "@vue/eslint-config-prettier": "^4.0.1",
61 | "@vue/eslint-config-typescript": "^4.0.0",
62 | "@vue/test-utils": "1.0.0-beta.29",
63 | "babel-eslint": "^10.0.1",
64 | "cross-env": "^5.2.0",
65 | "eslint": "^5.16.0",
66 | "eslint-config-prettier": "^4.1.0",
67 | "eslint-plugin-prettier": "^3.0.1",
68 | "eslint-plugin-react": "^7.12.4",
69 | "eslint-plugin-vue": "^5.2.2",
70 | "jest": "^24.7.1",
71 | "minimist": "^1.2.0",
72 | "nativescript-vue": "^2.2.2",
73 | "prettier": "^1.17.0",
74 | "rimraf": "^2.6.3",
75 | "rollup": "^1.10.0",
76 | "rollup-plugin-babel": "^4.3.2",
77 | "rollup-plugin-commonjs": "^9.3.4",
78 | "rollup-plugin-node-resolve": "^4.2.3",
79 | "rollup-plugin-replace": "^2.2.0",
80 | "rollup-plugin-terser": "^4.0.4",
81 | "rollup-plugin-typescript": "^1.0.1",
82 | "rollup-plugin-typescript2": "^0.20.1",
83 | "rollup-plugin-vue": "^5.0.0",
84 | "tns-core-modules": "^5.3.1",
85 | "ts-jest": "^24.0.2",
86 | "typescript": "^3.4.3",
87 | "vue": "^2.6.10",
88 | "vue-class-component": "^7.0.2",
89 | "vue-eslint-parser": "^6.0.3",
90 | "vue-property-decorator": "^8.1.0",
91 | "vue-template-compiler": "^2.6.10"
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/common/android-data.model.ts:
--------------------------------------------------------------------------------
1 | import { Shape } from './shape.enum';
2 |
3 | export type AndroidData = {
4 | elevation: number;
5 | pressedElevation?: number;
6 | shape?: Shape;
7 | bgcolor?: string;
8 | cornerRadius?: number;
9 | translationZ?: number;
10 | pressedTranslationZ?: number;
11 | forcePressAnimation?: boolean;
12 | }
--------------------------------------------------------------------------------
/src/common/elevation.enum.ts:
--------------------------------------------------------------------------------
1 | export enum Elevation {
2 | SWITCH = 1,
3 | CARD_RESTING = 2,
4 | RAISED_BUTTON_RESTING = 2,
5 | SEARCH_BAR_RESTING = 2,
6 | REFRESH_INDICADOR = 3,
7 | SEARCH_BAR_SCROLLED = 3,
8 | APPBAR = 4,
9 | FAB_RESTING = 6,
10 | SNACKBAR = 6,
11 | BOTTOM_NAVIGATION_BAR = 8,
12 | MENU = 8,
13 | CARD_PICKED_UP = 8,
14 | RAISED_BUTTON_PRESSED = 8,
15 | SUBMENU_LEVEL1 = 9,
16 | SUBMENU_LEVEL2 = 10,
17 | SUBMENU_LEVEL3 = 11,
18 | SUBMENU_LEVEL4 = 12,
19 | SUBMENU_LEVEL5 = 13,
20 | FAB_PRESSED = 12,
21 | NAV_DRAWER = 16,
22 | RIGHT_DRAWER = 16,
23 | MODAL_BOTTOM_SHEET = 16,
24 | DIALOG = 24,
25 | PICKER = 24,
26 | }
--------------------------------------------------------------------------------
/src/common/index.ts:
--------------------------------------------------------------------------------
1 | export * from './android-data.model';
2 | export * from './elevation.enum';
3 | export * from './ios-data.model';
4 | export * from './shadow';
5 | export * from './shape.enum';
--------------------------------------------------------------------------------
/src/common/ios-data.model.ts:
--------------------------------------------------------------------------------
1 | export type IOSData = {
2 | elevation: number;
3 | maskToBounds?: boolean;
4 | shadowColor?: string;
5 | shadowOffset?: number;
6 | shadowOpacity?: number;
7 | shadowRadius?: number;
8 | rasterize?: boolean;
9 | useShadowPath?: boolean;
10 | }
--------------------------------------------------------------------------------
/src/common/shadow.ts:
--------------------------------------------------------------------------------
1 | import { Color } from 'tns-core-modules/color';
2 |
3 | import { AndroidData } from "./android-data.model";
4 | import { IOSData } from "./ios-data.model";
5 | import { ShapeEnum } from './shape.enum';
6 | import { Length } from 'tns-core-modules/ui/page/page';
7 | import { isAndroid, screen } from "tns-core-modules/platform";
8 | import { Shape } from './shape.enum';
9 |
10 | declare const android: any;
11 | declare const java: any;
12 | declare const CGSizeMake: any;
13 | declare const UIScreen: any;
14 | declare const Array: any;
15 | declare const UIBezierPath: any;
16 |
17 | let LayeredShadow;
18 | let PlainShadow;
19 |
20 | if (isAndroid) {
21 | LayeredShadow = android.graphics.drawable.LayerDrawable.extend({});
22 | PlainShadow = android.graphics.drawable.GradientDrawable.extend({});
23 | }
24 |
25 | const classCache: { [id: string]: { class: any, fieldCache: { [id: string]: number } } } = {};
26 | // https://github.com/NativeScript/android-runtime/issues/1330
27 | function getAndroidR(rtype: string, field: string): number {
28 | const className = "android.R$" + rtype;
29 | if (!classCache.hasOwnProperty(className)) {
30 | classCache[className] = {
31 | class: java.lang.Class.forName(className),
32 | fieldCache: {}
33 | };
34 | }
35 | if(!classCache[className].fieldCache.hasOwnProperty(field)) {
36 | classCache[className].fieldCache[field] = +classCache[className].class.getField(field).get(null);
37 | }
38 | return classCache[className].fieldCache[field];
39 | }
40 |
41 | export class Shadow {
42 | static DEFAULT_SHAPE = ShapeEnum.RECTANGLE;
43 | static DEFAULT_BGCOLOR = '#FFFFFF';
44 | static DEFAULT_SHADOW_COLOR = '#000000';
45 | static DEFAULT_PRESSED_ELEVATION = 2;
46 | static DEFAULT_PRESSED_Z = 4;
47 |
48 | static apply(tnsView: any, data: IOSData | AndroidData) {
49 | const LOLLIPOP = 21;
50 | if (
51 | tnsView.android &&
52 | android.os.Build.VERSION.SDK_INT >= LOLLIPOP
53 | ) {
54 | Shadow.applyOnAndroid(tnsView, Shadow.getDefaults(data));
55 | } else if (tnsView.ios) {
56 | Shadow.applyOnIOS(tnsView, Shadow.getDefaults(data));
57 | }
58 | }
59 |
60 | private static getDefaults(data: IOSData | AndroidData) {
61 | return Object.assign(
62 | {},
63 | data,
64 | {
65 | shape: (data as AndroidData).shape || Shadow.DEFAULT_SHAPE,
66 | pressedElevation: (data as AndroidData).pressedElevation || Shadow.DEFAULT_PRESSED_ELEVATION,
67 | pressedTranslationZ: (data as AndroidData).pressedTranslationZ || Shadow.DEFAULT_PRESSED_ELEVATION,
68 | shadowColor: (data as IOSData).shadowColor ||
69 | Shadow.DEFAULT_SHADOW_COLOR,
70 | useShadowPath: ((data as IOSData).useShadowPath !== undefined ? (data as IOSData).useShadowPath : true),
71 | rasterize: ((data as IOSData).rasterize !== undefined ? (data as IOSData).rasterize : false)
72 | },
73 | );
74 | }
75 |
76 | private static isShadow(drawable: any): boolean {
77 | return (drawable instanceof LayeredShadow || drawable instanceof PlainShadow);
78 | }
79 |
80 | private static applyOnAndroid(tnsView: any, data: AndroidData) {
81 | const nativeView = tnsView.android;
82 | let shape;
83 | let overrideBackground = true;
84 |
85 |
86 | let currentBg = nativeView.getBackground();
87 |
88 | if (currentBg instanceof android.graphics.drawable.RippleDrawable) { // play nice if a ripple is wrapping a shadow
89 | let rippleBg = currentBg.getDrawable(0);
90 | if (rippleBg instanceof android.graphics.drawable.InsetDrawable) {
91 | overrideBackground = false; // this is a button with it's own shadow
92 | } else if (Shadow.isShadow(rippleBg)) { // if the ripple is wrapping a shadow, strip it
93 | currentBg = rippleBg;
94 | }
95 | }
96 | if (overrideBackground) {
97 | if (Shadow.isShadow(currentBg)) { // make sure to have the right background
98 | currentBg = currentBg instanceof LayeredShadow ? // if layered, get the original background
99 | currentBg.getDrawable(1) : null;
100 | }
101 |
102 | const outerRadii = Array.create("float", 8);
103 | if (data.cornerRadius === undefined) {
104 | outerRadii[0] = outerRadii[1] = Length.toDevicePixels(tnsView.borderTopLeftRadius, 0);
105 | outerRadii[2] = outerRadii[3] = Length.toDevicePixels(tnsView.borderTopRightRadius, 0);
106 | outerRadii[4] = outerRadii[5] = Length.toDevicePixels(tnsView.borderBottomRightRadius, 0);
107 | outerRadii[6] = outerRadii[7] = Length.toDevicePixels(tnsView.borderBottomLeftRadius, 0);
108 | } else {
109 | java.util.Arrays.fill(outerRadii, Shadow.androidDipToPx(nativeView, data.cornerRadius as number));
110 | }
111 |
112 | // use the user defined color or the default in case the color is TRANSPARENT
113 | const bgColor = currentBg ?
114 | (currentBg instanceof android.graphics.drawable.ColorDrawable && currentBg.getColor() ?
115 | currentBg.getColor() : android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR)) :
116 | android.graphics.Color.parseColor(data.bgcolor || Shadow.DEFAULT_BGCOLOR);
117 |
118 | let newBg;
119 |
120 | if (data.shape !== ShapeEnum.RECTANGLE || data.bgcolor || !currentBg) { // replace background
121 | shape = new PlainShadow();
122 | shape.setShape(
123 | android.graphics.drawable.GradientDrawable[data.shape as Shape],
124 | );
125 | shape.setCornerRadii(outerRadii);
126 | shape.setColor(bgColor);
127 | newBg = shape;
128 | } else { // add a layer
129 | const r = new android.graphics.drawable.shapes.RoundRectShape(outerRadii, null, null);
130 | shape = new android.graphics.drawable.ShapeDrawable(r);
131 | shape.getPaint().setColor(bgColor);
132 | var arr = Array.create(android.graphics.drawable.Drawable, 2);
133 | arr[0] = shape;
134 | arr[1] = currentBg;
135 | const drawable = new LayeredShadow(arr);
136 | newBg = drawable;
137 | }
138 |
139 | nativeView.setBackgroundDrawable(newBg);
140 | }
141 |
142 | nativeView.setElevation(
143 | Shadow.androidDipToPx(nativeView, data.elevation as number),
144 | );
145 | nativeView.setTranslationZ(
146 | Shadow.androidDipToPx(nativeView, data.translationZ as number),
147 | );
148 | if (nativeView.getStateListAnimator() || data.forcePressAnimation) {
149 | this.overrideDefaultAnimator(nativeView, data);
150 | }
151 | }
152 |
153 | private static overrideDefaultAnimator(nativeView: any, data: AndroidData) {
154 | const sla = new android.animation.StateListAnimator();
155 |
156 | const ObjectAnimator = android.animation.ObjectAnimator;
157 | const AnimatorSet = android.animation.AnimatorSet;
158 | const shortAnimTime = getAndroidR("integer", "config_shortAnimTime");
159 |
160 | const buttonDuration =
161 | nativeView.getContext().getResources().getInteger(shortAnimTime) / 2;
162 | const pressedElevation = this.androidDipToPx(nativeView, data.pressedElevation as number);
163 | const pressedZ = this.androidDipToPx(nativeView, data.pressedTranslationZ as number);
164 | const elevation = this.androidDipToPx(nativeView, data.elevation);
165 | const z = this.androidDipToPx(nativeView, data.translationZ || 0);
166 |
167 | const pressedSet = new AnimatorSet();
168 | const notPressedSet = new AnimatorSet();
169 | const defaultSet = new AnimatorSet();
170 |
171 | pressedSet.playTogether(java.util.Arrays.asList([
172 | ObjectAnimator.ofFloat(nativeView, "translationZ", [pressedZ])
173 | .setDuration(buttonDuration),
174 | ObjectAnimator.ofFloat(nativeView, "elevation", [pressedElevation])
175 | .setDuration(0),
176 | ]));
177 | notPressedSet.playTogether(java.util.Arrays.asList([
178 | ObjectAnimator.ofFloat(nativeView, "translationZ", [z])
179 | .setDuration(buttonDuration),
180 | ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
181 | .setDuration(0),
182 | ]));
183 | defaultSet.playTogether(java.util.Arrays.asList([
184 | ObjectAnimator.ofFloat(nativeView, "translationZ", [0]).setDuration(0),
185 | ObjectAnimator.ofFloat(nativeView, "elevation", [0]).setDuration(0),
186 | ]));
187 |
188 | sla.addState(
189 | [getAndroidR("attr", "state_pressed"), getAndroidR("attr", "state_enabled")],
190 | pressedSet,
191 | );
192 | sla.addState([getAndroidR("attr", "state_enabled")], notPressedSet);
193 | sla.addState([], defaultSet);
194 | nativeView.setStateListAnimator(sla);
195 | }
196 |
197 | private static applyOnIOS(tnsView: any, data: IOSData) {
198 | const nativeView = tnsView.ios;
199 | const elevation = parseFloat(((data.elevation as number) - 0).toFixed(2));
200 | nativeView.layer.maskToBounds = false;
201 | nativeView.layer.shadowColor = new Color(data.shadowColor as string).ios.CGColor;
202 | nativeView.layer.shadowOffset =
203 | data.shadowOffset ?
204 | CGSizeMake(0, parseFloat(String(data.shadowOffset))) :
205 | CGSizeMake(0, 0.54 * elevation - 0.14);
206 | nativeView.layer.shadowOpacity =
207 | data.shadowOpacity ?
208 | parseFloat(String(data.shadowOpacity)) :
209 | 0.006 * elevation + 0.25;
210 | nativeView.layer.shadowRadius =
211 | data.shadowRadius ?
212 | parseFloat(String(data.shadowRadius)) :
213 | 0.66 * elevation - 0.5;
214 | nativeView.layer.shouldRasterize = data.rasterize;
215 | nativeView.layer.rasterizationScale = screen.mainScreen.scale;
216 | let shadowPath = null;
217 | if (data.useShadowPath) {
218 | shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(nativeView.bounds, nativeView.layer.shadowRadius).cgPath;
219 | }
220 | nativeView.layer.shadowPath = shadowPath;
221 | }
222 |
223 | static androidDipToPx(nativeView: any, dip: number) {
224 | const metrics = nativeView.getContext().getResources().getDisplayMetrics();
225 | return android.util.TypedValue.applyDimension(
226 | android.util.TypedValue.COMPLEX_UNIT_DIP,
227 | dip,
228 | metrics,
229 | );
230 | }
231 | }
--------------------------------------------------------------------------------
/src/common/shape.enum.ts:
--------------------------------------------------------------------------------
1 | export enum ShapeEnum {
2 | RECTANGLE = 'RECTANGLE',
3 | OVAL = 'OVAL',
4 | RING = 'RING',
5 | LINE = 'LINE',
6 | }
7 |
8 | export type Shape = 'RECTANGLE' | 'OVAL' | 'RING' | 'LINE';
9 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { VueConstructor, PluginFunction } from 'vue';
2 |
3 | // Import directive
4 | import { ShadowDirective } from './vue-shadow';
5 |
6 | export function install(Vue: VueConstructor): void {
7 |
8 | if(install.installed) {
9 | console.log('not installed')
10 | return;
11 | } else {
12 | install.installed = true;
13 | Vue.directive('shadow', ShadowDirective);
14 | }
15 | };
16 |
17 | class NSVueShadow {
18 | static install: PluginFunction;
19 | }
20 |
21 | export namespace install {
22 | export let installed: boolean;
23 | }
24 |
25 | NSVueShadow.install = install;
26 |
27 | // To auto-install when vue is found
28 | /* global window global */
29 | let GlobalVue!: VueConstructor;
30 | if (typeof window !== "undefined" && typeof (window as any).Vue !== 'undefined') {
31 | GlobalVue = (window as any).Vue;
32 | } else if (typeof global !== "undefined" && typeof global['Vue'] !== 'undefined') {
33 | GlobalVue = global['Vue'];
34 | }
35 | if (GlobalVue) {
36 | GlobalVue.use(NSVueShadow);
37 | }
38 |
39 | export * from './common';
40 | export default NSVueShadow;
41 |
--------------------------------------------------------------------------------
/src/vue-shadow.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'nativescript-vue';
2 | import { DirectiveOptions, VNodeDirective, VNode } from 'vue';
3 | import { isAndroid, isIOS } from 'tns-core-modules/platform';
4 |
5 | import { AndroidData } from './common/android-data.model';
6 | import { IOSData } from './common/ios-data.model';
7 | import { Shadow } from './common/shadow';
8 | import { Shape } from './common/shape.enum';
9 | import { View } from 'tns-core-modules/ui/page/page';
10 | import { StackLayout } from 'tns-core-modules/ui/layouts/stack-layout';
11 | import { addWeakEventListener, removeWeakEventListener } from "tns-core-modules/ui/core/weak-event-listener";
12 | declare const android: any;
13 |
14 | export interface ShadowBindings extends VNodeDirective {
15 | value?: string | number | AndroidData | IOSData;
16 | }
17 |
18 | export class NativeShadowDirective {
19 |
20 | private el: any;
21 | private shadow!: string | number | AndroidData | IOSData;
22 | private elevation?: number | string;
23 |
24 | // along with this.elevation the following make up AndroidData object
25 | private pressedElevation?: number | string;
26 | private shape?: Shape;
27 | private bgcolor?: string;
28 | private cornerRadius?: number | string;
29 | private translationZ?: number | string;
30 | private pressedTranslationZ?: number | string;
31 | private forcePressAnimation?: boolean;
32 |
33 | // along with this.elevation the following make up IOSData object
34 | private maskToBounds?: boolean;
35 | private shadowColor?: string;
36 | private shadowOffset?: number | string;
37 | private shadowOpacity?: number | string;
38 | private shadowRadius?: number | string;
39 | private rasterize?: boolean;
40 | private useShadowPath?: boolean;
41 |
42 | // used to manage state
43 | private loaded = false;
44 | private initialized = false;
45 | private originalNSFn: any;
46 | private previousNSFn: any;
47 | private iosShadowWrapper!: View;
48 | private eventsBound = false;
49 |
50 | constructor(el: HTMLElement, binding: ShadowBindings) {
51 | this.el = el;
52 |
53 | if (binding.value && typeof binding.value !== 'object' && (typeof binding.value === 'string' || typeof binding.value === 'number') ) {
54 | this.shadow = binding.value;
55 | this.elevation = binding.value;
56 | }
57 |
58 | if (binding.value && typeof binding.value === 'object' && binding.value.elevation) {
59 | this.shadow = binding.value;
60 | this.elevation = this.shadow.elevation;
61 | if (isAndroid && (
62 | ('pressedElevation' in this.shadow) ||
63 | ('shape' in this.shadow) ||
64 | ('bgcolor' in this.shadow) ||
65 | ('cornerRadius' in this.shadow) ||
66 | ('translationZ' in this.shadow) ||
67 | ('pressedTranslationZ' in this.shadow) ||
68 | ('forcePressAnimation' in this.shadow)
69 | )) {
70 | this.pressedElevation = this.shadow.pressedElevation;
71 | this.shape= this.shadow.shape;
72 | this.bgcolor = this.shadow.bgcolor;
73 | this.cornerRadius = this.shadow.cornerRadius;
74 | this.translationZ = this.shadow.translationZ;
75 | this.pressedTranslationZ = this.shadow.pressedTranslationZ;
76 | this.forcePressAnimation= this.shadow.forcePressAnimation;
77 | } else if (isIOS && (
78 | ('maskToBounds' in this.shadow) ||
79 | ('shadowColor' in this.shadow) ||
80 | ('shadowOffset' in this.shadow) ||
81 | ('shadowOpacity' in this.shadow) ||
82 | ('shadowRadius' in this.shadow) ||
83 | ('useShadowPath' in this.shadow) ||
84 | ('rasterize' in this.shadow)
85 | )) {
86 | this.maskToBounds = this.shadow.maskToBounds;
87 | this.shadowColor = this.shadow.shadowColor;
88 | this.shadowOffset = this.shadow.shadowOffset;
89 | this.shadowOpacity = this.shadow.shadowOpacity;
90 | this.shadowRadius = this.shadow.shadowRadius;
91 | this.useShadowPath = this.shadow.useShadowPath;
92 | this.rasterize = this.shadow.rasterize;
93 | } else {
94 | //
95 | }
96 | }
97 |
98 | if (isAndroid) {
99 | if(this.el._nativeView._redrawNativeBackground) {
100 | this.originalNSFn = this.el._nativeView._redrawNativeBackground; //always store the original method
101 | }
102 | }
103 | }
104 |
105 | private initializeCommonData(): void {
106 | const tShadow = typeof this.shadow;
107 | if ((tShadow === 'string' || tShadow === 'number') && !this.elevation) {
108 | this.elevation = this.shadow ? parseInt(this.shadow as string, 10) : 2;
109 | }
110 | const tElevation = typeof this.elevation;
111 | if (tElevation === 'string' || tElevation === 'number') {
112 | this.elevation = this.elevation ? parseInt(this.elevation as string, 10) : 2;
113 | }
114 | }
115 |
116 | private initializeAndroidData(): void {
117 | if (typeof this.cornerRadius === 'string') {
118 | this.cornerRadius = parseInt(this.cornerRadius, 10);
119 | }
120 | if (typeof this.translationZ === 'string') {
121 | this.translationZ = parseInt(this.translationZ, 10);
122 | }
123 | }
124 |
125 | private initializeIOSData(): void {
126 | if (typeof this.shadowOffset === 'string') {
127 | this.shadowOffset = parseFloat(this.shadowOffset);
128 | }
129 | if (typeof this.shadowOpacity === 'string') {
130 | this.shadowOpacity = parseFloat(this.shadowOpacity);
131 | }
132 | if (typeof this.shadowRadius === 'string') {
133 | this.shadowRadius = parseFloat(this.shadowRadius);
134 | }
135 | }
136 |
137 | // Following sections (bindEvents & unbindEvents) of code is left in for historical purposes until more extensive testing
138 | // can be undertaken with the Vue version of the plugin. Commenting them out has no ill effects for Android,
139 | // but for IOS, the initial render has no shadows. If the v-shadow value is updated post render, then it will work
140 |
141 | // NS ListViews create elements dynamically
142 | // loaded and unloaded are called before angular is "ready"
143 | // https://github.com/NativeScript/nativescript-angular/issues/1221#issuecomment-422813111
144 | // So we ensure we're running loaded/unloaded events outside of angular
145 | private bindEvents(): void {
146 | if (!this.eventsBound) {
147 | addWeakEventListener(this.el._nativeView, View.loadedEvent, this.load, this);
148 | addWeakEventListener(this.el._nativeView, View.unloadedEvent, this.unload, this);
149 | this.eventsBound = true;
150 | // in some cases, the element is already loaded by time of binding
151 | if (this.el._nativeView.isLoaded) {
152 | this.load();
153 | }
154 | }
155 | }
156 |
157 | private unbindEvents(): void {
158 | if (this.eventsBound) {
159 | removeWeakEventListener(this.el._nativeView, View.loadedEvent, this.load, this);
160 | removeWeakEventListener(this.el._nativeView, View.unloadedEvent, this.unload, this);
161 | this.eventsBound = false;
162 | }
163 | }
164 |
165 | private load(): void {
166 | this.loaded = true;
167 |
168 | this.applyShadow();
169 | if (isAndroid) {
170 | this.previousNSFn = this.el._nativeView._redrawNativeBackground; // just to maintain compatibility with other patches
171 | this.el._nativeView._redrawNativeBackground = this.monkeyPatch;
172 | }
173 | }
174 |
175 | private unload(): void {
176 | this.loaded = false;
177 |
178 | if (isAndroid) {
179 | this.el._nativeView._redrawNativeBackground = this.originalNSFn; // always revert to the original method
180 | }
181 | }
182 |
183 | private monkeyPatch = (val): void => {
184 | this.previousNSFn.call(this.el._nativeView, val);
185 | this.applyShadow();
186 | };
187 |
188 | private applyShadow(): void {
189 | if (!this.shadow && !this.elevation) {
190 | return;
191 | }
192 |
193 | // For shadows to be shown on Android the SDK has to be greater
194 | // or equal than 21, lower SDK means no setElevation method is available
195 | if (isAndroid) {
196 | if (android.os.Build.VERSION.SDK_INT < 21) {
197 | return;
198 | }
199 | }
200 |
201 | const viewToApplyShadowTo = isIOS ? this.iosShadowWrapper : this.el._nativeView;
202 |
203 | if (viewToApplyShadowTo) {
204 | Shadow.apply(viewToApplyShadowTo, {
205 | elevation: this.elevation as number,
206 |
207 | // along with this.elevation the following make up AndroidData object
208 | pressedElevation: this.pressedElevation as number,
209 | shape: this.shape,
210 | bgcolor: this.bgcolor,
211 | cornerRadius: this.cornerRadius,
212 | translationZ: this.translationZ,
213 | pressedTranslationZ: this.pressedTranslationZ,
214 | forcePressAnimation: this.forcePressAnimation,
215 |
216 | // along with this.elevation the following make up IOSData object
217 | maskToBounds: this.maskToBounds,
218 | shadowColor: this.shadowColor,
219 | shadowOffset: this.shadowOffset as number,
220 | shadowOpacity: this.shadowOpacity as number,
221 | shadowRadius: this.shadowRadius as number,
222 | rasterize: this.rasterize,
223 | useShadowPath: this.useShadowPath
224 | });
225 | }
226 | }
227 |
228 | private loadFromAndroidData(data: AndroidData): void {
229 | this.elevation = data.elevation || this.elevation;
230 | this.shape = data.shape || this.shape;
231 | this.bgcolor = data.bgcolor || this.bgcolor;
232 | this.cornerRadius = data.cornerRadius || this.cornerRadius;
233 | this.translationZ = data.translationZ || this.translationZ;
234 | this.pressedTranslationZ = data.pressedTranslationZ || this.pressedTranslationZ;
235 | this.forcePressAnimation = data.forcePressAnimation || this.forcePressAnimation;
236 | }
237 |
238 | private loadFromIOSData(data: IOSData): void {
239 | this.maskToBounds = data.maskToBounds || this.maskToBounds;
240 | this.shadowColor = data.shadowColor || this.shadowColor;
241 | this.shadowOffset = data.shadowOffset || this.shadowOffset;
242 | this.shadowOpacity = data.shadowOpacity || this.shadowOpacity;
243 | this.shadowRadius = data.shadowRadius || this.shadowRadius;
244 | this.rasterize = data.rasterize || this.rasterize;
245 | this.useShadowPath = data.useShadowPath || this.useShadowPath;
246 | }
247 |
248 | public init(): void { // RadListView calls this multiple times for the same view
249 | if (!this.initialized) {
250 | this.initialized = true;
251 | this.initializeCommonData();
252 | if (isAndroid) {
253 | this.initializeAndroidData();
254 | } else if (isIOS) {
255 | this.initializeIOSData();
256 | }
257 | if (this.shadow && (this.shadow as AndroidData | IOSData).elevation) {
258 | if (isAndroid) {
259 | this.loadFromAndroidData(this.shadow as AndroidData);
260 | } else if (isIOS) {
261 | this.loadFromIOSData(this.shadow as IOSData);
262 | }
263 | }
264 |
265 | if (!this.shadow && this.elevation) {
266 | if (isAndroid) {
267 | this.loadFromAndroidData({
268 | elevation: this.elevation,
269 | pressedElevation: this.pressedElevation,
270 | shape: this.shape,
271 | bgcolor: this.bgcolor,
272 | cornerRadius: this.cornerRadius,
273 | translationZ: this.translationZ,
274 | pressedTranslationZ: this.pressedTranslationZ,
275 | forcePressAnimation: this.forcePressAnimation,
276 | } as AndroidData);
277 | } else if (isIOS) {
278 | this.loadFromIOSData({
279 | elevation: this.elevation,
280 | maskToBounds: this.maskToBounds,
281 | shadowColor: this.shadowColor,
282 | shadowOffset: this.shadowOffset as number,
283 | shadowOpacity: this.shadowOpacity as number,
284 | shadowRadius: this.shadowRadius as number,
285 | rasterize: this.rasterize,
286 | useShadowPath: this.useShadowPath
287 | } as IOSData);
288 | }
289 | }
290 |
291 | this.bindEvents();
292 | }
293 | }
294 |
295 | public addIOSWrapper(): void {
296 | if (isIOS) {
297 | const originalElement = this.el;
298 | const parent = originalElement.parentNode;
299 |
300 | const vm = new Vue({
301 | template: '',
302 | }).$mount();
303 |
304 | // @ts-ignore
305 | const wrapper = vm.$el;
306 |
307 | parent.insertBefore(wrapper, originalElement);
308 | parent.removeChild(originalElement);
309 | wrapper.appendChild(originalElement);
310 |
311 | // @ts-ignore
312 | this.iosShadowWrapper = wrapper._nativeView as StackLayout;
313 | }
314 | }
315 |
316 | public onUpdate(values: string | number | AndroidData | IOSData) {
317 | if (this.loaded && !!values) {
318 | if (typeof values !== 'object' && (typeof values === 'string' || typeof values === 'number')) {
319 | this.shadow = values;
320 | this.elevation = values;
321 | }
322 | if (typeof values === 'object' && values.elevation) {
323 | this.shadow = values;
324 | this.elevation = this.shadow.elevation;
325 | if (isAndroid) {
326 | this.loadFromAndroidData(this.shadow as AndroidData);
327 | } else if (isIOS) {
328 | this.loadFromIOSData(this.shadow as IOSData);
329 | }
330 | }
331 |
332 | this.applyShadow();
333 | }
334 | }
335 |
336 | public destroy(): void {
337 | if (this.initialized) {
338 | this.unload();
339 | this.unbindEvents();
340 | this.initialized = false;
341 | }
342 | }
343 | }
344 |
345 | export const ShadowDirective: DirectiveOptions = {
346 |
347 | bind(el: HTMLElement, binding: ShadowBindings, vnode: VNode) {
348 | // console.log("v-shadow - bind")
349 | const shadowDir: NativeShadowDirective = new NativeShadowDirective(el, binding);
350 | shadowDir.init();
351 | // @ts-ignore
352 | el.__vShadow = shadowDir;
353 | },
354 | inserted(el: HTMLElement, binding: ShadowBindings, vnode: VNode) {
355 | // console.log("v-shadow - inserted")
356 | // @ts-ignore
357 | const shadowDir = el.__vShadow
358 | shadowDir.addIOSWrapper();
359 | },
360 | update(el: HTMLElement, { value }, vnode: VNode) {
361 | // console.log("v-shadow - update")
362 | // console.log("v-shadow - update - value - ", value);
363 | // @ts-ignore
364 | const shadowDir = el.__vShadow
365 | shadowDir.onUpdate(value as string | number | AndroidData | IOSData);
366 | },
367 | unbind(el: HTMLElement, binding: ShadowBindings, vnode: VNode) {
368 | // console.log("v-shadow - unbind")
369 | // @ts-ignore
370 | const shadowDir = el.__vShadow
371 | shadowDir.destroy();
372 | // @ts-ignore
373 | el.__vShadow = null;
374 |
375 | },
376 | };
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/tests/unit/example.spec.ts:
--------------------------------------------------------------------------------
1 | import { shallowMount } from "@vue/test-utils";
2 | import HelloWorld from "@/components/HelloWorld.vue";
3 |
4 | describe("HelloWorld.vue", () => {
5 | it("renders props.msg when passed", () => {
6 | const msg = "new message";
7 | const wrapper = shallowMount(HelloWorld, {
8 | propsData: { msg }
9 | });
10 | expect(wrapper.text()).toMatch(msg);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/tests/unit/plugin.spec.ts:
--------------------------------------------------------------------------------
1 | // import { shallowMount, createLocalVue } from '@vue/test-utils'
2 | // // import HelloWorld from '@/components/HelloWorld.vue'
3 | // import plugin from '../../src/entry'
4 | // // import { PluginAddFunction } from '../../types/dyanmo'
5 |
6 | // // describe('Plugin', () => {
7 | // // it('should be 2', () => {
8 | // // const msg = 'new message'
9 | // // const localVue = createLocalVue()
10 | // // localVue.use(plugin)
11 | // // const wrapper = shallowMount(HelloWorld, {
12 | // // localVue,
13 | // // propsData: { msg }
14 | // // })
15 | // // expect(wrapper.vm.$add(1, 1)).toBe(2)
16 | // // })
17 | // // })
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "outDir": "dist",
5 | "module": "esnext",
6 | "strict": true,
7 | "jsx": "preserve",
8 | "importHelpers": true,
9 | "moduleResolution": "node",
10 | "experimentalDecorators": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "sourceMap": true,
14 | "baseUrl": ".",
15 | "resolveJsonModule": true,
16 | "declaration": true,
17 | "declarationDir": "types",
18 | "allowJs": false,
19 | "strictNullChecks": true,
20 | "noImplicitAny": false,
21 | "removeComments": true,
22 | "types": [
23 | "node",
24 | "jest"
25 | ],
26 | "paths": {
27 | "@/*": [
28 | "src/*"
29 | ]
30 | },
31 | "lib": [
32 | "esnext",
33 | "dom",
34 | "dom.iterable",
35 | "scripthost"
36 | ]
37 | },
38 | "include": [
39 | "src/**/*",
40 | "types/vue-shims.d.ts"
41 | ],
42 | "exclude": [
43 | "node_modules",
44 | "dist",
45 | "demo"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/types/common/android-data.model.d.ts:
--------------------------------------------------------------------------------
1 | import { Shape } from './shape.enum';
2 | export declare type AndroidData = {
3 | elevation: number;
4 | pressedElevation?: number;
5 | shape?: Shape;
6 | bgcolor?: string;
7 | cornerRadius?: number;
8 | translationZ?: number;
9 | pressedTranslationZ?: number;
10 | forcePressAnimation?: boolean;
11 | };
12 |
--------------------------------------------------------------------------------
/types/common/elevation.enum.d.ts:
--------------------------------------------------------------------------------
1 | export declare enum Elevation {
2 | SWITCH = 1,
3 | CARD_RESTING = 2,
4 | RAISED_BUTTON_RESTING = 2,
5 | SEARCH_BAR_RESTING = 2,
6 | REFRESH_INDICADOR = 3,
7 | SEARCH_BAR_SCROLLED = 3,
8 | APPBAR = 4,
9 | FAB_RESTING = 6,
10 | SNACKBAR = 6,
11 | BOTTOM_NAVIGATION_BAR = 8,
12 | MENU = 8,
13 | CARD_PICKED_UP = 8,
14 | RAISED_BUTTON_PRESSED = 8,
15 | SUBMENU_LEVEL1 = 9,
16 | SUBMENU_LEVEL2 = 10,
17 | SUBMENU_LEVEL3 = 11,
18 | SUBMENU_LEVEL4 = 12,
19 | SUBMENU_LEVEL5 = 13,
20 | FAB_PRESSED = 12,
21 | NAV_DRAWER = 16,
22 | RIGHT_DRAWER = 16,
23 | MODAL_BOTTOM_SHEET = 16,
24 | DIALOG = 24,
25 | PICKER = 24
26 | }
27 |
--------------------------------------------------------------------------------
/types/common/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from './android-data.model';
2 | export * from './elevation.enum';
3 | export * from './ios-data.model';
4 | export * from './shadow';
5 | export * from './shape.enum';
6 |
--------------------------------------------------------------------------------
/types/common/ios-data.model.d.ts:
--------------------------------------------------------------------------------
1 | export declare type IOSData = {
2 | elevation: number;
3 | maskToBounds?: boolean;
4 | shadowColor?: string;
5 | shadowOffset?: number;
6 | shadowOpacity?: number;
7 | shadowRadius?: number;
8 | rasterize?: boolean;
9 | useShadowPath?: boolean;
10 | };
11 |
--------------------------------------------------------------------------------
/types/common/shadow.d.ts:
--------------------------------------------------------------------------------
1 | import { AndroidData } from "./android-data.model";
2 | import { IOSData } from "./ios-data.model";
3 | import { ShapeEnum } from './shape.enum';
4 | export declare class Shadow {
5 | static DEFAULT_SHAPE: ShapeEnum;
6 | static DEFAULT_BGCOLOR: string;
7 | static DEFAULT_SHADOW_COLOR: string;
8 | static DEFAULT_PRESSED_ELEVATION: number;
9 | static DEFAULT_PRESSED_Z: number;
10 | static apply(tnsView: any, data: IOSData | AndroidData): void;
11 | private static getDefaults;
12 | private static isShadow;
13 | private static applyOnAndroid;
14 | private static overrideDefaultAnimator;
15 | private static applyOnIOS;
16 | static androidDipToPx(nativeView: any, dip: number): any;
17 | }
18 |
--------------------------------------------------------------------------------
/types/common/shape.enum.d.ts:
--------------------------------------------------------------------------------
1 | export declare enum ShapeEnum {
2 | RECTANGLE = "RECTANGLE",
3 | OVAL = "OVAL",
4 | RING = "RING",
5 | LINE = "LINE"
6 | }
7 | export declare type Shape = 'RECTANGLE' | 'OVAL' | 'RING' | 'LINE';
8 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | import { VueConstructor, PluginFunction } from 'vue';
2 | export declare function install(Vue: VueConstructor): void;
3 | declare class NSVueShadow {
4 | static install: PluginFunction;
5 | }
6 | export declare namespace install {
7 | let installed: boolean;
8 | }
9 | export * from './common';
10 | export default NSVueShadow;
11 |
--------------------------------------------------------------------------------
/types/vue-shadow.d.ts:
--------------------------------------------------------------------------------
1 | import { DirectiveOptions, VNodeDirective } from 'vue';
2 | import { AndroidData } from './common/android-data.model';
3 | import { IOSData } from './common/ios-data.model';
4 | export interface ShadowBindings extends VNodeDirective {
5 | value?: string | number | AndroidData | IOSData;
6 | }
7 | export declare class NativeShadowDirective {
8 | private el;
9 | private shadow;
10 | private elevation?;
11 | private pressedElevation?;
12 | private shape?;
13 | private bgcolor?;
14 | private cornerRadius?;
15 | private translationZ?;
16 | private pressedTranslationZ?;
17 | private forcePressAnimation?;
18 | private maskToBounds?;
19 | private shadowColor?;
20 | private shadowOffset?;
21 | private shadowOpacity?;
22 | private shadowRadius?;
23 | private rasterize?;
24 | private useShadowPath?;
25 | private loaded;
26 | private initialized;
27 | private originalNSFn;
28 | private previousNSFn;
29 | private iosShadowWrapper;
30 | private eventsBound;
31 | constructor(el: HTMLElement, binding: ShadowBindings);
32 | private initializeCommonData;
33 | private initializeAndroidData;
34 | private initializeIOSData;
35 | private bindEvents;
36 | private unbindEvents;
37 | private load;
38 | private unload;
39 | private monkeyPatch;
40 | private applyShadow;
41 | private loadFromAndroidData;
42 | private loadFromIOSData;
43 | init(): void;
44 | addIOSWrapper(): void;
45 | onUpdate(values: string | number | AndroidData | IOSData): void;
46 | destroy(): void;
47 | }
48 | export declare const ShadowDirective: DirectiveOptions;
49 |
--------------------------------------------------------------------------------
/types/vue-shims.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module "*.vue" {
3 | import Vue from "vue";
4 | export default Vue;
5 | }
--------------------------------------------------------------------------------