├── .circleci
└── config.yml
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── .yarnrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── example
├── .expo-shared
│ └── assets.json
├── App.js
├── app.json
├── assets
│ ├── adaptive-icon.png
│ ├── favicon.png
│ ├── icon.png
│ └── splash.png
├── babel.config.js
├── metro.config.js
├── package.json
├── src
│ ├── App.tsx
│ └── assets
│ │ └── default.jpg
├── webpack.config.js
└── yarn.lock
├── lefthook.yml
├── package.json
├── scripts
└── bootstrap.js
├── src
├── Avatar
│ ├── icons
│ │ ├── ic-avatar.png
│ │ └── ic-camera.png
│ ├── index.tsx
│ ├── styles.ts
│ └── type.ts
├── Image
│ ├── index.tsx
│ └── type.ts
├── __tests__
│ └── index.test.tsx
└── index.tsx
├── tsconfig.build.json
├── tsconfig.json
└── yarn.lock
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | executors:
4 | default:
5 | docker:
6 | - image: circleci/node:16
7 | working_directory: ~/project
8 |
9 | commands:
10 | attach_project:
11 | steps:
12 | - attach_workspace:
13 | at: ~/project
14 |
15 | jobs:
16 | install-dependencies:
17 | executor: default
18 | steps:
19 | - checkout
20 | - attach_project
21 | - restore_cache:
22 | keys:
23 | - dependencies-{{ checksum "package.json" }}
24 | - dependencies-
25 | - restore_cache:
26 | keys:
27 | - dependencies-example-{{ checksum "example/package.json" }}
28 | - dependencies-example-
29 | - run:
30 | name: Install dependencies
31 | command: |
32 | yarn install --cwd example --frozen-lockfile
33 | yarn install --frozen-lockfile
34 | - save_cache:
35 | key: dependencies-{{ checksum "package.json" }}
36 | paths: node_modules
37 | - save_cache:
38 | key: dependencies-example-{{ checksum "example/package.json" }}
39 | paths: example/node_modules
40 | - persist_to_workspace:
41 | root: .
42 | paths: .
43 |
44 | lint:
45 | executor: default
46 | steps:
47 | - attach_project
48 | - run:
49 | name: Lint files
50 | command: |
51 | yarn lint
52 |
53 | typescript:
54 | executor: default
55 | steps:
56 | - attach_project
57 | - run:
58 | name: Typecheck files
59 | command: |
60 | yarn typescript
61 |
62 | unit-tests:
63 | executor: default
64 | steps:
65 | - attach_project
66 | - run:
67 | name: Run unit tests
68 | command: |
69 | yarn test --coverage
70 | - store_artifacts:
71 | path: coverage
72 | destination: coverage
73 |
74 | build-package:
75 | executor: default
76 | steps:
77 | - attach_project
78 | - run:
79 | name: Build package
80 | command: |
81 | yarn prepare
82 |
83 | workflows:
84 | build-and-test:
85 | jobs:
86 | - install-dependencies
87 | - lint:
88 | requires:
89 | - install-dependencies
90 | - typescript:
91 | requires:
92 | - install-dependencies
93 | - unit-tests:
94 | requires:
95 | - install-dependencies
96 | - build-package:
97 | requires:
98 | - install-dependencies
99 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 |
9 | indent_style = space
10 | indent_size = 2
11 |
12 | end_of_line = lf
13 | charset = utf-8
14 | trim_trailing_whitespace = true
15 | insert_final_newline = true
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 | # specific for windows script files
3 | *.bat text eol=crlf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # XDE
6 | .expo/
7 |
8 | # VSCode
9 | .vscode/
10 | jsconfig.json
11 |
12 | # Xcode
13 | #
14 | build/
15 | *.pbxuser
16 | !default.pbxuser
17 | *.mode1v3
18 | !default.mode1v3
19 | *.mode2v3
20 | !default.mode2v3
21 | *.perspectivev3
22 | !default.perspectivev3
23 | xcuserdata
24 | *.xccheckout
25 | *.moved-aside
26 | DerivedData
27 | *.hmap
28 | *.ipa
29 | *.xcuserstate
30 | project.xcworkspace
31 |
32 | # Android/IJ
33 | #
34 | .classpath
35 | .cxx
36 | .gradle
37 | .idea
38 | .project
39 | .settings
40 | local.properties
41 | android.iml
42 |
43 | # Cocoapods
44 | #
45 | example/ios/Pods
46 |
47 | # Ruby
48 | example/vendor/
49 |
50 | # node.js
51 | #
52 | node_modules/
53 | npm-debug.log
54 | yarn-debug.log
55 | yarn-error.log
56 |
57 | # BUCK
58 | buck-out/
59 | \.buckd/
60 | android/app/libs
61 | android/keystores/debug.keystore
62 |
63 | # Expo
64 | .expo/*
65 |
66 | # generated by bob
67 | lib/
68 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/.yarnrc:
--------------------------------------------------------------------------------
1 | # Override Yarn command so we can automatically setup the repo on running `yarn`
2 |
3 | yarn-path "scripts/bootstrap.js"
4 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributor Covenant Code of Conduct
3 |
4 | ## Our Pledge
5 |
6 | We as members, contributors, and leaders pledge to make participation in our
7 | community a harassment-free experience for everyone, regardless of age, body
8 | size, visible or invisible disability, ethnicity, sex characteristics, gender
9 | identity and expression, level of experience, education, socio-economic status,
10 | nationality, personal appearance, race, caste, color, religion, or sexual
11 | identity and orientation.
12 |
13 | We pledge to act and interact in ways that contribute to an open, welcoming,
14 | diverse, inclusive, and healthy community.
15 |
16 | ## Our Standards
17 |
18 | Examples of behavior that contributes to a positive environment for our
19 | community include:
20 |
21 | * Demonstrating empathy and kindness toward other people
22 | * Being respectful of differing opinions, viewpoints, and experiences
23 | * Giving and gracefully accepting constructive feedback
24 | * Accepting responsibility and apologizing to those affected by our mistakes,
25 | and learning from the experience
26 | * Focusing on what is best not just for us as individuals, but for the overall
27 | community
28 |
29 | Examples of unacceptable behavior include:
30 |
31 | * The use of sexualized language or imagery, and sexual attention or advances of
32 | any kind
33 | * Trolling, insulting or derogatory comments, and personal or political attacks
34 | * Public or private harassment
35 | * Publishing others' private information, such as a physical or email address,
36 | without their explicit permission
37 | * Other conduct which could reasonably be considered inappropriate in a
38 | professional setting
39 |
40 | ## Enforcement Responsibilities
41 |
42 | Community leaders are responsible for clarifying and enforcing our standards of
43 | acceptable behavior and will take appropriate and fair corrective action in
44 | response to any behavior that they deem inappropriate, threatening, offensive,
45 | or harmful.
46 |
47 | Community leaders have the right and responsibility to remove, edit, or reject
48 | comments, commits, code, wiki edits, issues, and other contributions that are
49 | not aligned to this Code of Conduct, and will communicate reasons for moderation
50 | decisions when appropriate.
51 |
52 | ## Scope
53 |
54 | This Code of Conduct applies within all community spaces, and also applies when
55 | an individual is officially representing the community in public spaces.
56 | Examples of representing our community include using an official e-mail address,
57 | posting via an official social media account, or acting as an appointed
58 | representative at an online or offline event.
59 |
60 | ## Enforcement
61 |
62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
63 | reported to the community leaders responsible for enforcement at
64 | [INSERT CONTACT METHOD].
65 | All complaints will be reviewed and investigated promptly and fairly.
66 |
67 | All community leaders are obligated to respect the privacy and security of the
68 | reporter of any incident.
69 |
70 | ## Enforcement Guidelines
71 |
72 | Community leaders will follow these Community Impact Guidelines in determining
73 | the consequences for any action they deem in violation of this Code of Conduct:
74 |
75 | ### 1. Correction
76 |
77 | **Community Impact**: Use of inappropriate language or other behavior deemed
78 | unprofessional or unwelcome in the community.
79 |
80 | **Consequence**: A private, written warning from community leaders, providing
81 | clarity around the nature of the violation and an explanation of why the
82 | behavior was inappropriate. A public apology may be requested.
83 |
84 | ### 2. Warning
85 |
86 | **Community Impact**: A violation through a single incident or series of
87 | actions.
88 |
89 | **Consequence**: A warning with consequences for continued behavior. No
90 | interaction with the people involved, including unsolicited interaction with
91 | those enforcing the Code of Conduct, for a specified period of time. This
92 | includes avoiding interactions in community spaces as well as external channels
93 | like social media. Violating these terms may lead to a temporary or permanent
94 | ban.
95 |
96 | ### 3. Temporary Ban
97 |
98 | **Community Impact**: A serious violation of community standards, including
99 | sustained inappropriate behavior.
100 |
101 | **Consequence**: A temporary ban from any sort of interaction or public
102 | communication with the community for a specified period of time. No public or
103 | private interaction with the people involved, including unsolicited interaction
104 | with those enforcing the Code of Conduct, is allowed during this period.
105 | Violating these terms may lead to a permanent ban.
106 |
107 | ### 4. Permanent Ban
108 |
109 | **Community Impact**: Demonstrating a pattern of violation of community
110 | standards, including sustained inappropriate behavior, harassment of an
111 | individual, or aggression toward or disparagement of classes of individuals.
112 |
113 | **Consequence**: A permanent ban from any sort of public interaction within the
114 | community.
115 |
116 | ## Attribution
117 |
118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119 | version 2.1, available at
120 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
121 |
122 | Community Impact Guidelines were inspired by
123 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
124 |
125 | For answers to common questions about this code of conduct, see the FAQ at
126 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
127 | [https://www.contributor-covenant.org/translations][translations].
128 |
129 | [homepage]: https://www.contributor-covenant.org
130 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
131 | [Mozilla CoC]: https://github.com/mozilla/diversity
132 | [FAQ]: https://www.contributor-covenant.org/faq
133 | [translations]: https://www.contributor-covenant.org/translations
134 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are always welcome, no matter how large or small!
4 |
5 | We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./CODE_OF_CONDUCT.md).
6 |
7 | ## Development workflow
8 |
9 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package:
10 |
11 | ```sh
12 | yarn
13 | ```
14 |
15 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development.
16 |
17 | While developing, you can run the [example app](/example/) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app.
18 |
19 | To start the packager:
20 |
21 | ```sh
22 | yarn example start
23 | ```
24 |
25 | To run the example app on Android:
26 |
27 | ```sh
28 | yarn example android
29 | ```
30 |
31 | To run the example app on iOS:
32 |
33 | ```sh
34 | yarn example ios
35 | ```
36 |
37 | To run the example app on Web:
38 |
39 | ```sh
40 | yarn example web
41 | ```
42 |
43 | Make sure your code passes TypeScript and ESLint. Run the following to verify:
44 |
45 | ```sh
46 | yarn typescript
47 | yarn lint
48 | ```
49 |
50 | To fix formatting errors, run the following:
51 |
52 | ```sh
53 | yarn lint --fix
54 | ```
55 |
56 | Remember to add tests for your change if possible. Run the unit tests by:
57 |
58 | ```sh
59 | yarn test
60 | ```
61 |
62 | ### Commit message convention
63 |
64 | We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages:
65 |
66 | - `fix`: bug fixes, e.g. fix crash due to deprecated method.
67 | - `feat`: new features, e.g. add new method to the module.
68 | - `refactor`: code refactor, e.g. migrate from class components to hooks.
69 | - `docs`: changes into documentation, e.g. add usage example for the module..
70 | - `test`: adding or updating tests, e.g. add integration tests using detox.
71 | - `chore`: tooling changes, e.g. change CI config.
72 |
73 | Our pre-commit hooks verify that your commit message matches this format when committing.
74 |
75 | ### Linting and tests
76 |
77 | [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/)
78 |
79 | We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing.
80 |
81 | Our pre-commit hooks verify that the linter and tests pass when committing.
82 |
83 | ### Publishing to npm
84 |
85 | We use [release-it](https://github.com/release-it/release-it) to make it easier to publish new versions. It handles common tasks like bumping version based on semver, creating tags and releases etc.
86 |
87 | To publish new versions, run the following:
88 |
89 | ```sh
90 | yarn release
91 | ```
92 |
93 | ### Scripts
94 |
95 | The `package.json` file contains various scripts for common tasks:
96 |
97 | - `yarn bootstrap`: setup project by installing all dependencies and pods.
98 | - `yarn typescript`: type-check files with TypeScript.
99 | - `yarn lint`: lint files with ESLint.
100 | - `yarn test`: run unit tests with Jest.
101 | - `yarn example start`: start the Metro server for the example app.
102 | - `yarn example android`: run the example app on Android.
103 | - `yarn example ios`: run the example app on iOS.
104 |
105 | ### Sending a pull request
106 |
107 | > **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).
108 |
109 | When you're sending a pull request:
110 |
111 | - Prefer small pull requests focused on one change.
112 | - Verify that linters and tests are passing.
113 | - Review the documentation to make sure it looks good.
114 | - Follow the pull request template when opening a pull request.
115 | - For pull requests that change the API or implementation, discuss with maintainers first by opening an issue.
116 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Hoa Phan
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## react-native-element-image
2 |
3 | Automatically calculate width or height based on input Image component for React Native.
4 |
5 | #### Source code demo
6 |
7 | - [react-native-template-components](https://github.com/hoaphantn7604/react-native-template-components) A beautiful template for React Native.
8 |
9 | ## Getting started
10 |
11 | ```js
12 | npm install react-native-element-image --save
13 | ```
14 |
15 | or
16 |
17 | ```js
18 | yarn add npm install react-native-element-image
19 | ```
20 |
21 | #### Demo
22 |
23 | 
24 |
25 | #### Image Props
26 |
27 | | Props | Params | isRequire | Description |
28 | | ---------- | ------------------- | --------- | ----------------------------- |
29 | | source | ImageSourcePropType | Yes | |
30 | | width | Number | | Fixed width, automatic height |
31 | | height | Number | | Fixed height, automatic width |
32 | | background | Boolean | No | if true is Image Background |
33 | | onSize | (size) => void | No | get Image size |
34 |
35 | #### Avatar Props
36 |
37 | | Props | Params | isRequire | Description |
38 | | -------------- | ------------------- | --------- | ----------------------- |
39 | | containerStyle | ViewStyle | No | |
40 | | size | Number | No | Default is 100px |
41 | | source | ImageSourcePropType | Yes | |
42 | | borderColor | String | No | Default is white |
43 | | name | String | No | |
44 | | nameStyle | TextStyle | No | |
45 | | iconEnable | Boolean | No | Default is true |
46 | | renderIcon | Element | No | Customize icon camera |
47 | | onPressIcon | ()=> void | No | Event click icon camera |
48 |
49 | ## Usage
50 |
51 | ```javascript
52 | import React from 'react';
53 | import { StyleSheet, View, Text } from 'react-native';
54 | import { Image, Avatar } from 'react-native-element-image';
55 | const img = require('./assets/default.png');
56 |
57 | const ImageScreen = (_props) => {
58 | return (
59 |
60 | alert('Click')}
66 | nameStyle={{ fontSize: 20 }}
67 | />
68 | alert('Click')}
74 | nameStyle={{ fontSize: 20 }}
75 | />
76 |
77 | alert('Click')}
83 | name="User name"
84 | nameStyle={{ fontSize: 20, marginBottom: 20 }}
85 | />
86 | Width: 200, Height: Automatic
87 |
88 | Width: Automatic, Height: 200
89 |
90 |
91 | );
92 | };
93 |
94 | export default ImageScreen;
95 |
96 | const styles = StyleSheet.create({
97 | container: {
98 | flex: 1,
99 | justifyContent: 'center',
100 | alignItems: 'center',
101 | },
102 | image: {
103 | margin: 20,
104 | },
105 | text: { marginTop: 50 },
106 | avatar: { marginTop: 10 },
107 | });
108 | ```
109 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/example/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/example/App.js:
--------------------------------------------------------------------------------
1 | export { default } from './src/App';
2 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "example",
4 | "slug": "example",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "userInterfaceStyle": "light",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "contain",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "updates": {
15 | "fallbackToCacheTimeout": 0
16 | },
17 | "assetBundlePatterns": [
18 | "**/*"
19 | ],
20 | "ios": {
21 | "supportsTablet": true
22 | },
23 | "android": {
24 | "adaptiveIcon": {
25 | "foregroundImage": "./assets/adaptive-icon.png",
26 | "backgroundColor": "#FFFFFF"
27 | }
28 | },
29 | "web": {
30 | "favicon": "./assets/favicon.png"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/example/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/example/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/example/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/example/assets/favicon.png
--------------------------------------------------------------------------------
/example/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/example/assets/icon.png
--------------------------------------------------------------------------------
/example/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/example/assets/splash.png
--------------------------------------------------------------------------------
/example/babel.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const pak = require('../package.json');
3 |
4 | module.exports = function (api) {
5 | api.cache(true);
6 |
7 | return {
8 | presets: ['babel-preset-expo'],
9 | plugins: [
10 | [
11 | 'module-resolver',
12 | {
13 | extensions: ['.tsx', '.ts', '.js', '.json'],
14 | alias: {
15 | // For development, we want to alias the library to the source
16 | [pak.name]: path.join(__dirname, '..', pak.source),
17 | },
18 | },
19 | ],
20 | ],
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/example/metro.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const escape = require('escape-string-regexp');
3 | const { getDefaultConfig } = require('@expo/metro-config');
4 | const exclusionList = require('metro-config/src/defaults/exclusionList');
5 | const pak = require('../package.json');
6 |
7 | const root = path.resolve(__dirname, '..');
8 |
9 | const modules = Object.keys({
10 | ...pak.peerDependencies,
11 | });
12 |
13 | const defaultConfig = getDefaultConfig(__dirname);
14 |
15 | module.exports = {
16 | ...defaultConfig,
17 |
18 | projectRoot: __dirname,
19 | watchFolders: [root],
20 |
21 | // We need to make sure that only one version is loaded for peerDependencies
22 | // So we block them at the root, and alias them to the versions in example's node_modules
23 | resolver: {
24 | ...defaultConfig.resolver,
25 |
26 | blacklistRE: exclusionList(
27 | modules.map(
28 | (m) =>
29 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
30 | )
31 | ),
32 |
33 | extraNodeModules: modules.reduce((acc, name) => {
34 | acc[name] = path.join(__dirname, 'node_modules', name);
35 | return acc;
36 | }, {}),
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "main": "node_modules/expo/AppEntry.js",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web"
10 | },
11 | "dependencies": {
12 | "expo": "~46.0.16",
13 | "expo-status-bar": "~1.4.0",
14 | "react": "18.0.0",
15 | "react-native": "0.69.6"
16 | },
17 | "devDependencies": {
18 | "@babel/core": "^7.12.9",
19 | "babel-plugin-module-resolver": "^4.1.0"
20 | },
21 | "private": true
22 | }
23 |
--------------------------------------------------------------------------------
/example/src/App.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-native/no-inline-styles */
2 | import React from 'react';
3 | import { StyleSheet, View, Text, Alert, ScrollView } from 'react-native';
4 | import { Image, Avatar } from 'react-native-element-image';
5 | const img = require('./assets/default.jpg');
6 |
7 | const ImageScreen = (_props: any) => {
8 | return (
9 |
10 |
11 | Alert.alert('Click')}
17 | nameStyle={{ fontSize: 20 }}
18 | />
19 | Alert.alert('Click')}
25 | nameStyle={{ fontSize: 20 }}
26 | />
27 |
28 | Alert.alert('Click')}
34 | name="User name"
35 | nameStyle={{ fontSize: 20, marginBottom: 20 }}
36 | />
37 | Width: 150, Height: Automatic
38 |
39 | Width: Automatic, Height: 200
40 |
41 |
42 |
43 | );
44 | };
45 |
46 | export default ImageScreen;
47 |
48 | const styles = StyleSheet.create({
49 | container: {
50 | flex: 1,
51 | justifyContent: 'center',
52 | alignItems: 'center',
53 | paddingVertical: 20,
54 | },
55 | image: {
56 | margin: 20,
57 | },
58 | text: { marginTop: 50 },
59 | avatar: { marginTop: 10 },
60 | });
61 |
--------------------------------------------------------------------------------
/example/src/assets/default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/example/src/assets/default.jpg
--------------------------------------------------------------------------------
/example/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const createExpoWebpackConfigAsync = require('@expo/webpack-config');
3 | const { resolver } = require('./metro.config');
4 |
5 | const root = path.resolve(__dirname, '..');
6 | const node_modules = path.join(__dirname, 'node_modules');
7 |
8 | module.exports = async function (env, argv) {
9 | const config = await createExpoWebpackConfigAsync(env, argv);
10 |
11 | config.module.rules.push({
12 | test: /\.(js|jsx|ts|tsx)$/,
13 | include: path.resolve(root, 'src'),
14 | use: 'babel-loader',
15 | });
16 |
17 | // We need to make sure that only one version is loaded for peerDependencies
18 | // So we alias them to the versions in example's node_modules
19 | Object.assign(config.resolve.alias, {
20 | ...resolver.extraNodeModules,
21 | 'react-native-web': path.join(node_modules, 'react-native-web'),
22 | });
23 |
24 | return config;
25 | };
26 |
--------------------------------------------------------------------------------
/lefthook.yml:
--------------------------------------------------------------------------------
1 | pre-commit:
2 | parallel: true
3 | commands:
4 | lint:
5 | files: git diff --name-only @{push}
6 | glob: "*.{js,ts,jsx,tsx}"
7 | run: npx eslint {files}
8 | types:
9 | files: git diff --name-only @{push}
10 | glob: "*.{js,ts, jsx, tsx}"
11 | run: npx tsc --noEmit
12 | commit-msg:
13 | parallel: true
14 | commands:
15 | commitlint:
16 | run: npx commitlint --edit
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-element-image",
3 | "version": "1.1.1",
4 | "description": "Automatically calculate width or height based on input Image component for React Native.",
5 | "main": "lib/commonjs/index",
6 | "module": "lib/module/index",
7 | "types": "lib/typescript/index.d.ts",
8 | "react-native": "src/index",
9 | "source": "src/index",
10 | "files": [
11 | "src",
12 | "lib",
13 | "android",
14 | "ios",
15 | "cpp",
16 | "*.podspec",
17 | "!lib/typescript/example",
18 | "!ios/build",
19 | "!android/build",
20 | "!android/gradle",
21 | "!android/gradlew",
22 | "!android/gradlew.bat",
23 | "!android/local.properties",
24 | "!**/__tests__",
25 | "!**/__fixtures__",
26 | "!**/__mocks__",
27 | "!**/.*"
28 | ],
29 | "scripts": {
30 | "test": "jest",
31 | "typescript": "tsc --noEmit",
32 | "lint": "eslint \"**/*.{js,ts,tsx}\"",
33 | "prepare": "bob build",
34 | "release": "release-it",
35 | "example": "yarn --cwd example",
36 | "bootstrap": "yarn example && yarn install"
37 | },
38 | "keywords": [
39 | "react-native",
40 | "elements",
41 | "components",
42 | "image",
43 | "auto width",
44 | "auto height",
45 | "image scale",
46 | "user avatar"
47 | ],
48 | "repository": "https://github.com/hoaphantn7604/react-native-element-image",
49 | "author": "Hoa Phan (https://github.com/hoaphantn7604)",
50 | "license": "MIT",
51 | "bugs": {
52 | "url": "https://github.com/hoaphantn7604/react-native-element-image/issues"
53 | },
54 | "homepage": "https://github.com/hoaphantn7604/react-native-element-image#readme",
55 | "publishConfig": {
56 | "registry": "https://registry.npmjs.org/"
57 | },
58 | "devDependencies": {
59 | "@arkweid/lefthook": "^0.7.7",
60 | "@commitlint/config-conventional": "^17.0.2",
61 | "@react-native-community/eslint-config": "^3.0.2",
62 | "@release-it/conventional-changelog": "^5.0.0",
63 | "@types/jest": "^28.1.2",
64 | "@types/react": "~17.0.21",
65 | "@types/react-native": "0.70.0",
66 | "commitlint": "^17.0.2",
67 | "eslint": "^8.4.1",
68 | "eslint-config-prettier": "^8.5.0",
69 | "eslint-plugin-prettier": "^4.0.0",
70 | "jest": "^28.1.1",
71 | "pod-install": "^0.1.0",
72 | "prettier": "^2.0.5",
73 | "react": "18.0.0",
74 | "react-native": "0.69.6",
75 | "react-native-builder-bob": "^0.20.0",
76 | "release-it": "^15.0.0",
77 | "typescript": "^4.5.2"
78 | },
79 | "resolutions": {
80 | "@types/react": "17.0.21"
81 | },
82 | "peerDependencies": {
83 | "react": "*",
84 | "react-native": "*"
85 | },
86 | "jest": {
87 | "preset": "react-native",
88 | "modulePathIgnorePatterns": [
89 | "/example/node_modules",
90 | "/lib/"
91 | ]
92 | },
93 | "commitlint": {
94 | "extends": [
95 | "@commitlint/config-conventional"
96 | ]
97 | },
98 | "release-it": {
99 | "git": {
100 | "commitMessage": "chore: release ${version}",
101 | "tagName": "v${version}"
102 | },
103 | "npm": {
104 | "publish": true
105 | },
106 | "github": {
107 | "release": true
108 | },
109 | "plugins": {
110 | "@release-it/conventional-changelog": {
111 | "preset": "angular"
112 | }
113 | }
114 | },
115 | "eslintConfig": {
116 | "root": true,
117 | "extends": [
118 | "@react-native-community",
119 | "prettier"
120 | ],
121 | "rules": {
122 | "prettier/prettier": [
123 | "error",
124 | {
125 | "quoteProps": "consistent",
126 | "singleQuote": true,
127 | "tabWidth": 2,
128 | "trailingComma": "es5",
129 | "useTabs": false
130 | }
131 | ]
132 | }
133 | },
134 | "eslintIgnore": [
135 | "node_modules/",
136 | "lib/"
137 | ],
138 | "prettier": {
139 | "quoteProps": "consistent",
140 | "singleQuote": true,
141 | "tabWidth": 2,
142 | "trailingComma": "es5",
143 | "useTabs": false
144 | },
145 | "react-native-builder-bob": {
146 | "source": "src",
147 | "output": "lib",
148 | "targets": [
149 | "commonjs",
150 | "module",
151 | [
152 | "typescript",
153 | {
154 | "project": "tsconfig.build.json"
155 | }
156 | ]
157 | ]
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/scripts/bootstrap.js:
--------------------------------------------------------------------------------
1 | const os = require('os');
2 | const path = require('path');
3 | const child_process = require('child_process');
4 |
5 | const root = path.resolve(__dirname, '..');
6 | const args = process.argv.slice(2);
7 | const options = {
8 | cwd: process.cwd(),
9 | env: process.env,
10 | stdio: 'inherit',
11 | encoding: 'utf-8',
12 | };
13 |
14 | if (os.type() === 'Windows_NT') {
15 | options.shell = true;
16 | }
17 |
18 | let result;
19 |
20 | if (process.cwd() !== root || args.length) {
21 | // We're not in the root of the project, or additional arguments were passed
22 | // In this case, forward the command to `yarn`
23 | result = child_process.spawnSync('yarn', args, options);
24 | } else {
25 | // If `yarn` is run without arguments, perform bootstrap
26 | result = child_process.spawnSync('yarn', ['bootstrap'], options);
27 | }
28 |
29 | process.exitCode = result.status;
30 |
--------------------------------------------------------------------------------
/src/Avatar/icons/ic-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/src/Avatar/icons/ic-avatar.png
--------------------------------------------------------------------------------
/src/Avatar/icons/ic-camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoaphantn7604/react-native-element-image/89f9432af3f84c9c0ab2cecb17cfda9d80a9519c/src/Avatar/icons/ic-camera.png
--------------------------------------------------------------------------------
/src/Avatar/index.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-native/no-inline-styles */
2 | import React, { useMemo } from 'react';
3 | import { View, TouchableWithoutFeedback } from 'react-native';
4 | import type { AvatarProps } from './type';
5 | import { Image, Text } from 'react-native';
6 | import { styles } from './styles';
7 |
8 | const img_avatar = require('./icons/ic-avatar.png');
9 | const img_camera = require('./icons/ic-camera.png');
10 |
11 | const AvatarComponent: AvatarProps = (props) => {
12 | const {
13 | containerStyle = {},
14 | size = 100,
15 | borderColor = 'white',
16 | name,
17 | nameStyle,
18 | iconEnable = true,
19 | renderIcon,
20 | onPressIcon,
21 | } = props;
22 |
23 | const _renderIcon = () => {
24 | if (iconEnable) {
25 | if (renderIcon) {
26 | return renderIcon;
27 | } else {
28 | return (
29 | {
31 | onPressIcon && onPressIcon();
32 | }}
33 | >
34 |
44 |
52 |
53 |
54 | );
55 | }
56 | }
57 | return null;
58 | };
59 |
60 | const uri = useMemo(() => {
61 | if (props.source) {
62 | return props.source;
63 | }
64 | return img_avatar;
65 | }, [props.source]);
66 |
67 | return (
68 |
69 |
79 |
84 | {_renderIcon()}
85 |
86 | {name ? {name} : null}
87 |
88 | );
89 | };
90 |
91 | export default AvatarComponent;
92 |
--------------------------------------------------------------------------------
/src/Avatar/styles.ts:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | export const styles = StyleSheet.create({
4 | container: {
5 | justifyContent: 'center',
6 | alignItems: 'center',
7 | },
8 | name: {
9 | fontSize: 14,
10 | fontWeight: '500',
11 | marginTop: 8,
12 | },
13 | });
14 |
--------------------------------------------------------------------------------
/src/Avatar/type.ts:
--------------------------------------------------------------------------------
1 | import type React from 'react';
2 | import type { ImageProps, TextStyle, ViewStyle } from 'react-native';
3 |
4 | interface Props extends ImageProps {
5 | containerStyle?: ViewStyle;
6 | size?: number;
7 | borderColor?: string;
8 | name?: string;
9 | nameStyle?: TextStyle;
10 | iconEnable?: boolean;
11 | renderIcon?: JSX.Element | undefined;
12 | onPressIcon?: () => void;
13 | }
14 |
15 | export type AvatarProps = React.FC;
16 |
--------------------------------------------------------------------------------
/src/Image/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from 'react';
2 | import { Image, ImageBackground } from 'react-native';
3 | import type { PropsImage } from './type';
4 |
5 | const resolveAssetSource = Image.resolveAssetSource;
6 |
7 | const ImageAuto: PropsImage = (props) => {
8 | const { style = {}, onSize = () => {}, background } = props;
9 | const [autoWidth, setAutoWidth] = useState(null);
10 | const [autoHeight, setAutoHeight] = useState(null);
11 | const mounted = useRef(false);
12 |
13 | useEffect(() => {
14 | mounted.current = true;
15 |
16 | return () => {
17 | mounted.current = false;
18 | };
19 | }, []);
20 |
21 | useEffect(() => {
22 | onProps(props);
23 | });
24 |
25 | const onProps = (localProps: any) => {
26 | const { source } = localProps;
27 | if (source.uri) {
28 | const sourceToUse = source.uri ? source.uri : source;
29 |
30 | Image.getSize(
31 | sourceToUse,
32 | (width, height) => adjustSize(width, height, props),
33 | console.log
34 | );
35 | } else {
36 | const sourceToUse = resolveAssetSource(source);
37 | adjustSize(sourceToUse.width, sourceToUse.height, props);
38 | }
39 | };
40 |
41 | const adjustSize = (
42 | sourceWidth: number,
43 | sourceHeight: number,
44 | localProps: any
45 | ) => {
46 | const { width, height } = localProps;
47 |
48 | let ratio = 1;
49 |
50 | if (width && height) {
51 | ratio = Math.min(width / sourceWidth, height / sourceHeight);
52 | } else if (width) {
53 | ratio = width / sourceWidth;
54 | } else if (height) {
55 | ratio = height / sourceHeight;
56 | }
57 |
58 | if (mounted.current) {
59 | const ratioWidth = sourceWidth * ratio;
60 | const ratioHeight = sourceHeight * ratio;
61 |
62 | setAutoWidth(ratioWidth);
63 | setAutoHeight(ratioHeight);
64 | if (onSize) {
65 | onSize({ width: ratioWidth, height: ratioHeight });
66 | }
67 | }
68 | };
69 |
70 | if (autoWidth && autoHeight) {
71 | if (background) {
72 | return (
73 |
77 | );
78 | }
79 | return (
80 |
84 | );
85 | }
86 | return null;
87 | };
88 |
89 | export default ImageAuto;
90 |
--------------------------------------------------------------------------------
/src/Image/type.ts:
--------------------------------------------------------------------------------
1 | import type React from 'react';
2 | import type { ImageBackgroundProps, ImageStyle } from 'react-native';
3 |
4 | interface onSize {
5 | width: number;
6 | height: number;
7 | }
8 |
9 | interface Props extends ImageBackgroundProps {
10 | style?: ImageStyle;
11 | height?: number;
12 | width?: number;
13 | background?: boolean;
14 | onSize?: (size: onSize) => void;
15 | }
16 |
17 | export type PropsImage = React.FC;
18 |
--------------------------------------------------------------------------------
/src/__tests__/index.test.tsx:
--------------------------------------------------------------------------------
1 | it.todo('write a test');
2 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import Image from './Image';
2 | import Avatar from './Avatar';
3 |
4 | export { Image, Avatar };
5 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "extends": "./tsconfig",
4 | "exclude": ["example"]
5 | }
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "react-native-element-image": ["./src/index"]
6 | },
7 | "allowUnreachableCode": false,
8 | "allowUnusedLabels": false,
9 | "esModuleInterop": true,
10 | "importsNotUsedAsValues": "error",
11 | "forceConsistentCasingInFileNames": true,
12 | "jsx": "react",
13 | "lib": ["esnext"],
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "noFallthroughCasesInSwitch": true,
17 | "noImplicitReturns": true,
18 | "noImplicitUseStrict": false,
19 | "noStrictGenericChecks": false,
20 | "noUncheckedIndexedAccess": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | "resolveJsonModule": true,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "target": "esnext"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------