diff --git a/.eslintignore b/.eslintignore
index d3e8a6328bc4..396bfd28c614 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,3 +1,4 @@
**/node_modules/*
**/dist/*
.github/actions/**/index.js"
+docs/vendor/**
diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml
index 3e54975433f6..cdb95bd66779 100644
--- a/.github/workflows/typecheck.yml
+++ b/.github/workflows/typecheck.yml
@@ -5,7 +5,7 @@ on:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
- paths: ['**.ts', '**.tsx', 'package.json', 'package-lock.json', 'tsconfig.json']
+ paths: ['**.js', '**.ts', '**.tsx', 'package.json', 'package-lock.json', 'tsconfig.json']
jobs:
typecheck:
@@ -20,3 +20,12 @@ jobs:
run: npm run typecheck
env:
CI: true
+
+ - name: Check for new JavaScript files
+ run: |
+ git fetch origin main --no-tags --depth=1
+ count_new_js=$(git diff --name-only --diff-filter=A origin/main HEAD -- 'src/libs/*.js' 'src/hooks/*.js' 'src/styles/*.js' 'src/languages/*.js' | wc -l)
+ if [ "$count_new_js" -gt "0" ]; then
+ echo "ERROR: Found new JavaScript files in the /src/libs, /src/hooks, /src/styles, or /src/languages directories; use TypeScript instead."
+ exit 1
+ fi
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 70cd7e39dda5..56159149c5e1 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -96,8 +96,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001039900
- versionName "1.3.99-0"
+ versionCode 1001040000
+ versionName "1.4.0-0"
}
flavorDimensions "default"
diff --git a/assets/images/empty-state__attach-receipt.svg b/assets/images/empty-state__attach-receipt.svg
new file mode 100644
index 000000000000..6b50afbdbf0b
--- /dev/null
+++ b/assets/images/empty-state__attach-receipt.svg
@@ -0,0 +1,16 @@
+
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md
index 112c3b9617c9..f2ff837d7638 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md
@@ -1,5 +1,91 @@
---
-title: Connect Company Cards
-description: Connect Company Cards
+title: Company-Card-Settings.md
+description: Company card settings
---
-## Resource Coming Soon!
+# Overview
+Once you’ve imported your company cards via commercial card feed, direct bank feed, or CSV import, the next step is to configure the cards’ settings.
+
+As a Domain Admin, you can access the company card settings by navigating to Settings > Domains> Domain Name > Company Card > Settings.
+
+If you cannot access Domains, you will need to request Domain Admin access my the Domain Admin.
+
+# How to configure company card settings
+You can manage company cards and set and adjust the settings from the Domains page by navigating to Settings > Domains > [Domain name] > Settings
+
+## Reimbursable preference
+
+You can control how your employees' company card expenses are flagged for reimbursement:
+
+Force Yes: All expenses will be marked as reimbursable, and employees cannot change this setting.
+Force No: All expenses will be marked as non-reimbursable, and employees cannot change this setting.
+Do Not Force: Expenses will default to either reimbursable or non-reimbursable (your choice), but employees can adjust if necessary.
+
+## Liability type
+
+Choose the liability type that suits your needs:
+
+Corporate Liability: Users cannot delete company card expenses.
+Personal Liability: Users are allowed to delete company card expenses.
+
+If you update the settings on an existing company card feed, the changes will apply to expenses imported after the date the setting is saved. The update will not affect previously imported expenses.
+
+## Preferred policy
+
+Setting a preferred policy for a company card feed will ensure that the imported transactions are added to a report on the policy you set. This setting is useful when members are on multiple policies and need to ensure their company card expenses are reported to a particular policy.
+
+# How to use Scheduled Submit with company cards
+All expenses must be placed on a report if they need to be approved; with Scheduled Submit, you no longer need to worry about the arduous task of employees creating their expenses, adding them to a report, and submitting them manually. All they need to do is SmartScan their receipts and Concierge will take care of the rest, on a variety of schedules that you can set according to your preferences!
+
+Concierge won't automatically submit expenses on reports that have Expense Violations. Instead, these expenses will be moved to a new report, creating an additional report for the current reporting period.
+
+An employee can add comments in the Expense Comment field or at the bottom of the report to clarify any details.
+
+## Enable Scheduled Submit
+Scheduled Submit is enabled in the Group Policy by navigating to Settings > Policies > Group > Policy Name > Reports > Scheduled Submit
+Use the toggle to enable Scheduled Submit
+Choose your desired frequency
+
+If Scheduled Submit is disabled on the group policy level (or set to a manual frequency), and you have noticed expense reports are still automatically submitted to the group policy, it's likely Scheduled Submit is enabled on the user’s Individual Policy settings.
+
+# How to connect company cards to an accounting integration
+
+If you're using a connected accounting system such as NetSuite, Xero, Intacct, Quickbooks Desktop, or QuickBooks Online, you can also connect the card to export to a specific credit card GL account. First, connect the card itself, and once completed, follow the steps below:
+Go to Settings > Domains > Domain name > Company Cards
+Click Edit Exports on the right-hand side of the card table and select the GL account you want to export expenses to
+You're all done. After the account is set, exported expenses will be mapped to the specific account selected when exported by a Domain Admin.
+
+# How to export company card expenses to a connected accounting integration
+
+## Pooled GL account
+
+To export credit card expenses to a pooled GL account:
+Go to Settings > Policies > Group > Policy Name > Connections > Accounting Integrations > Configure
+Select Credit Card / Charge Card / Bank Transaction as your Non-reimbursable export option.
+Please review the Export Settings page for exporting Expense Reports to NetSuite
+Select the Vendor/liability account you want to export all non-reimbursable expenses to.
+
+## Individual GL account
+
+Go to Settings > Domain > Domain name > Company Cards
+Click the Export Settings cog to the right-hand side of the card and select the GL account you want to export expenses to.
+You're all done! After the account is set, exported expenses will be mapped to the specific account selected.
+
+# Deep Dive
+## Identifying company card transactions
+When you link your credit cards to Expensify, the transactions will appear in each user's account on the Expenses page as soon as they're posted. You can identify transactions from centrally managed cards by seeing the locked card icon next to them. That icon indicates that they’re company card expenses:
+[add image here]
+
+## Importing historical transactions
+
+After a card is connected via direct connection or via Approved! banks, Expensify will import 30-90 days' worth of historical transactions to your account (the timeframe is based on your bank's discretion). Any historical expenses beyond that date range can be imported using the CSV spreadsheet import method.
+
+## Using eReceipts
+Expensify eReceipts serve as digital substitutes for paper receipts in your purchase transactions, eliminating the necessity to retain physical receipts or utilize SmartScanning receipts. In the case of Expensify Card transactions, eReceipts are automatically generated for all amounts. For other card programs, eReceipts are specifically generated for purchases amounting to $75 or less, provided the transactions are in USD.
+To ensure seamless automatic importation, it's essential to maintain your transactions in US Dollars. Additionally, eReceipts can be directly imported from your bank account. Please be aware that CSV/OFX imported files of bank transactions do not support eReceipts.
+It's important to note that eReceipts are not generated for lodging expenses. Moreover, due to incomplete or inaccurate category information from certain banks, there may be instances of invalid eReceipts being generated for hotel purchases. If you choose to re-categorize expenses, a similar situation may arise. It's crucial to remember that our Expensify eReceipt Guarantee excludes coverage for hotel and motel expenses.
+
+# FAQ
+## What plan/subscription is required in order to manage corporate cards?
+Group Policy (Collect or Control plan only)
+## When do my company card transactions import to Expensify?
+Credit card transactions are imported to Expensify once they’re posted to the bank account. This usually takes 1-3 business days between the point of purchase and when the transactions populate in your account.
diff --git a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md
index 42a8a914e5bc..5431355dd790 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md
@@ -66,7 +66,7 @@ A Workspace admin can see Processing, Approved, and Reimbursed expenses as long
If employees submit expense reports on a workspace where you are not an admin, you will not have visibility into those expenses. Additionally, if an expense is left unreported, a workspace admin will not be able to see that expense until it’s been added to a report.
A Workspace admin can edit the tags and categories on an expense, but if they want to edit the amount, date, or merchant name, the expense will need to be in a Processing state or rejected back to the submitter for changes.
-We have more about company card expense reconciliation in this support article.
+We have more about company card expense reconciliation in this [support article](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation).
## Can I edit multiple expenses at once?
Yes! Select the expenses you want to edit and click **Edit Multiple**.
diff --git a/docs/articles/new-expensify/getting-started/Expensify-Lounge.md b/docs/articles/new-expensify/getting-started/Expensify-Lounge.md
deleted file mode 100644
index bdccbe927769..000000000000
--- a/docs/articles/new-expensify/getting-started/Expensify-Lounge.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Welcome to the Expensify Lounge!
-description: How to get the most out of the Expensify Lounge.
-redirect_from: articles/other/Expensify-Lounge/
----
-
-
-# What is the Expensify Lounge?
-The Expensify Lounge is a place where people go to Get Shit Done. It's a beautiful environment with great coffee and a group of people to collaborate with. Check out this guide on how to best utilize the Expensify Lounge!
-
-# The Two Rules
-### Rule #1 - Get Shit Done
-
-The Lounge is a space for people to get work done. It is optimized to be the perfect environment for you to focus on your work, collaborate with others, and advance your most wild and creative ideas. To make this a reality, we ask our members to keep the following in mind:
-
-- **#focus** - Use the space for how it was designed and do not distract from others' focus. The space is beautiful, social, and collaborative, but it was created to help our members work effectively.
-- **#urgency** - Working remotely is great, but there's nothing like real-time collaboration with your colleagues. Use the lounge to meet with co-workers IRL to continue the progress on whatever it is you're working on.
-- **#results** - Don't mistake time for effort or effort for output. Upon arrival, visualize what you want to accomplish, and don't leave until it's done.
-
-## Rule #2 - Don’t Ruin it for Everyone Else
-
-We want this place to be incredible, innovative, and always elvoving. To achieve that, we have some general guidelines:
-
-- **#writeitdown** - If you can help others learn from you, do so. Write a blog post, a document, or a post in Expensify Chat to share with others. This includes making the Expensify Lounge a better space. Feel free to write down any improvements so we can make it better.
-- **#showup** - If you are in the lounge, be fully present. Meet others, and collaborate in social rooms. The point is to build a community of people who are focused on getting shit done; you’ll get out what you put in.
-- **#oneteam** - Providing an inclusive community is our priority, and we do not tolerate any form of discrimination. Aim to go out of your way to include people who want to be included.
-- **#nocreeps** - Do not make people feel uncomfortable with your words or actions. If you are made to feel uncomfortable or notice this happening to someone else, you can use the escalation process outlined in the FAQ section.
-
-# How to Use the Expensify Lounge
-Keeping those two rules in mind, below is a guide on how our members can get the most out of the lounge.
-
-### Rule #1 - Getting Shit Done
-- **Order drinks from Concierge** - [Write Concierge here](https://new.expensify.com/concierge) to ask lounge questions or order beverages. Concierge will bring your order directly to you!
-- **Using an office** - Offices are first come, first serve. If an office is open, feel free to use it! Please keep office use to under an hour. We currently do not allow reserving offices.
-- **Lounge hours** - The lounge will be open from 8am-6pm PT, Monday through Friday and closed on some major holidays. You can review our Google Maps profile to check our holiday hours.
-- **Make the lounge better** - Make any suggestions to improve the lounge experience in [#announce - Expensify Lounge](https://new.expensify.com/r/8292963527436014).
-
-## Rule #2 - Not Ruining it for Everyone Else
-- **Offices are for calls** - Please do not occupy an office unless you have a call or collaborative meeting happening, and don't stay in an office for longer than an hour.
-- **Respect other people** - Please do not be too loud or distracting while others are trying to work. While collaborating in Expensify Chat, be respectful of others’ viewpoints and keep a positive environment.
-- **Stay home if you’re sick** - If you feel sick, please do not visit the lounge, or consider wearing a mask in public areas.
-- **If you see something, say something** - If you are made to feel uncomfortable or witness others being made uncomfortable, let Concierge know. If this is happening in Expensify Chat, use our moderation tools (outlined below in the FAQ) to apply the applicable level of moderation.
-
-We’re so happy you are here to live rich, have fun, and save the world with us. Now, go enjoy the Expensify Lounge, and let's Get Shit Done!
-
-# FAQs
-
-#### What is Concierge?
-
-Concierge is our automated system that answers member questions in real-time. Questions regarding the local lounge will be routed directly to the lounge's Concierge. You can send Concierge a message if you have a drink request or general questions. They’ll take care of everything for you!
-
-#### Who is invited to the Expensify Lounge?
-
-Everyone is invited to the Expensify Lounge! Whether you're an existing customer, or you're someone looking for a great space to Get Shit Done, we'd love to have you.
-
-#### How do I escalate something that's making me or someone else uncomfortable?
-
-If you see something in Expensify Chat that should be escalated, you can use the escalation feature to mark a chat as:
-- **Spam or Inconsiderate**: This will send a whisper to the sender of the message warning them of the violation, and the message will have a flag applied to it which will be visible to all users. Concierge will not review these flags.
-- **Intimidating or Bullying**: The message will be immediately hidden, and the content will be reviewed by our team. After reviewing the message, and it's confirmed intimidation or bullying, the message will be permanently hidden and we'll communicate the violation to the sender of the message.
-- **Harassment or Assault**: The message will be immediately hidden and reviewed by our team. The user will be sent a message to warning them of the violation, and Concierge can block the user if that's deemed necessary.
-
-If you witness something in-person, please write to Concierge referencing which lounge you are in, and they will escalate the issue appropriately.
-
-#### Where are other Expensify Lounge locations?
-
-Right now, we only have the San Francisco Lounge, but be on the lookout for more coming soon!
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index d40d36701731..0de3f7cb2671 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageTypeAPPLCFBundleShortVersionString
- 1.3.99
+ 1.4.0CFBundleSignature????CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.3.99.0
+ 1.4.0.0ITSAppUsesNonExemptEncryptionLSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 4e3ca3ebce6d..cd8b9bd630c8 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageTypeBNDLCFBundleShortVersionString
- 1.3.99
+ 1.4.0CFBundleSignature????CFBundleVersion
- 1.3.99.0
+ 1.4.0.0
diff --git a/package-lock.json b/package-lock.json
index 1f09b940b6db..feded2dd608b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.99-0",
+ "version": "1.4.0-0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.99-0",
+ "version": "1.4.0-0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index fbbd5024edf8..839046c66031 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.99-0",
+ "version": "1.4.0-0",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/patches/react-native-web+0.19.9+004+fix-pointer-events.patch b/patches/react-native-web+0.19.9+004+fix-pointer-events.patch
new file mode 100644
index 000000000000..a457fbcfe36c
--- /dev/null
+++ b/patches/react-native-web+0.19.9+004+fix-pointer-events.patch
@@ -0,0 +1,22 @@
+diff --git a/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js b/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js
+index bdcecc2..63f1364 100644
+--- a/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js
++++ b/node_modules/react-native-web/dist/exports/StyleSheet/compiler/index.js
+@@ -353,7 +353,7 @@ function createAtomicRules(identifier, property, value) {
+ var _block2 = createDeclarationBlock({
+ pointerEvents: 'none'
+ });
+- rules.push(selector + ">*" + _block2);
++ rules.push(selector + " *" + _block2);
+ }
+ } else if (value === 'none' || value === 'box-none') {
+ finalValue = 'none!important';
+@@ -361,7 +361,7 @@ function createAtomicRules(identifier, property, value) {
+ var _block3 = createDeclarationBlock({
+ pointerEvents: 'auto'
+ });
+- rules.push(selector + ">*" + _block3);
++ rules.push(selector + " *" + _block3);
+ }
+ }
+ var _block4 = createDeclarationBlock({
diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js
index 496093f96e0d..edc378ea3dd3 100644
--- a/src/components/AddPlaidBankAccount.js
+++ b/src/components/AddPlaidBankAccount.js
@@ -9,8 +9,8 @@ import useNetwork from '@hooks/useNetwork';
import KeyboardShortcut from '@libs/KeyboardShortcut';
import Log from '@libs/Log';
import {plaidDataPropTypes} from '@pages/ReimbursementAccount/plaidDataPropTypes';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import * as App from '@userActions/App';
import * as BankAccounts from '@userActions/BankAccounts';
import CONST from '@src/CONST';
@@ -83,6 +83,8 @@ function AddPlaidBankAccount({
allowDebit,
isPlaidDisabled,
}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const subscribedKeyboardShortcuts = useRef([]);
const previousNetworkState = useRef();
@@ -186,7 +188,7 @@ function AddPlaidBankAccount({
{lodashGet(plaidData, 'isLoading') && (
@@ -237,7 +239,7 @@ function AddPlaidBankAccount({
height={iconSize}
width={iconSize}
additionalStyles={iconStyles}
- fill={themeColors.icon}
+ fill={theme.icon}
/>
{bankName}
diff --git a/src/components/AddressSearch/CurrentLocationButton.js b/src/components/AddressSearch/CurrentLocationButton.js
index 326b82d31e8f..3c7feb8fb70c 100644
--- a/src/components/AddressSearch/CurrentLocationButton.js
+++ b/src/components/AddressSearch/CurrentLocationButton.js
@@ -7,8 +7,8 @@ import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import useLocalize from '@hooks/useLocalize';
import getButtonState from '@libs/getButtonState';
import colors from '@styles/colors';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
const propTypes = {
/** Callback that runs when location button is clicked */
@@ -24,6 +24,7 @@ const defaultProps = {
};
function CurrentLocationButton({onPress, isDisabled}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
return (
diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js
index 61460a93650e..73472beeb48d 100644
--- a/src/components/AddressSearch/index.js
+++ b/src/components/AddressSearch/index.js
@@ -14,9 +14,9 @@ import * as ApiUtils from '@libs/ApiUtils';
import compose from '@libs/compose';
import getCurrentPosition from '@libs/getCurrentPosition';
import * as GooglePlacesUtils from '@libs/GooglePlacesUtils';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import CurrentLocationButton from './CurrentLocationButton';
@@ -144,6 +144,8 @@ const defaultProps = {
// Relevant thread: https://expensify.slack.com/archives/C03TQ48KC/p1634088400387400
// Reference: https://github.com/FaridSafi/react-native-google-places-autocomplete/issues/609#issuecomment-886133839
function AddressSearch(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const [displayListViewBorder, setDisplayListViewBorder] = useState(false);
const [isTyping, setIsTyping] = useState(false);
const [isFocused, setIsFocused] = useState(false);
@@ -392,7 +394,7 @@ function AddressSearch(props) {
listLoaderComponent={
@@ -489,8 +491,8 @@ function AddressSearch(props) {
}}
numberOfLines={2}
isRowScrollable={false}
- listHoverColor={themeColors.border}
- listUnderlayColor={themeColors.buttonPressedBG}
+ listHoverColor={theme.border}
+ listUnderlayColor={theme.buttonPressedBG}
onLayout={(event) => {
// We use the height of the element to determine if we should hide the border of the listView dropdown
// to prevent a lingering border when there are no address suggestions.
diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index 43fd5e6a1b98..bd88712432a8 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import refPropTypes from './refPropTypes';
import TextInput from './TextInput';
@@ -39,6 +39,7 @@ const defaultProps = {
};
function AmountTextInput(props) {
+ const styles = useThemeStyles();
return (
() => {
ReportActionContextMenu.hideContextMenu();
diff --git a/src/components/AnonymousReportFooter.js b/src/components/AnonymousReportFooter.js
index 2dc4159d1627..387e2ab01930 100644
--- a/src/components/AnonymousReportFooter.js
+++ b/src/components/AnonymousReportFooter.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import {Text, View} from 'react-native';
import reportPropTypes from '@pages/reportPropTypes';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import * as Session from '@userActions/Session';
import AvatarWithDisplayName from './AvatarWithDisplayName';
import Button from './Button';
@@ -29,6 +29,7 @@ const defaultProps = {
};
function AnonymousReportFooter(props) {
+ const styles = useThemeStyles();
return (
diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js
index 52484355a242..b1fac827d273 100644
--- a/src/components/ArchivedReportFooter.js
+++ b/src/components/ArchivedReportFooter.js
@@ -9,7 +9,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import personalDetailsPropType from '@pages/personalDetailsPropType';
import reportPropTypes from '@pages/reportPropTypes';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import Banner from './Banner';
@@ -50,6 +50,7 @@ const defaultProps = {
};
function ArchivedReportFooter(props) {
+ const styles = useThemeStyles();
const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT);
let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [props.report.ownerAccountID, 'displayName']);
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index 16a2adaacf4b..50646ecb2534 100755
--- a/src/components/AttachmentModal.js
+++ b/src/components/AttachmentModal.js
@@ -19,9 +19,9 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import useNativeDriver from '@libs/useNativeDriver';
import reportPropTypes from '@pages/reportPropTypes';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import * as IOU from '@userActions/IOU';
import * as Policy from '@userActions/Policy';
import CONST from '@src/CONST';
@@ -112,6 +112,8 @@ const defaultProps = {
};
function AttachmentModal(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const onModalHideCallbackRef = useRef(null);
const [isModalOpen, setIsModalOpen] = useState(props.defaultOpen);
const [shouldLoadAttachment, setShouldLoadAttachment] = useState(false);
@@ -412,7 +414,7 @@ function AttachmentModal(props) {
onSubmit={submitAndClose}
onClose={closeModal}
isVisible={isModalOpen}
- backgroundColor={themeColors.componentBG}
+ backgroundColor={theme.componentBG}
onModalShow={() => {
props.onModalShow();
setShouldLoadAttachment(true);
diff --git a/src/components/AttachmentPicker/index.native.js b/src/components/AttachmentPicker/index.native.js
index 0e723d4cf048..5b955ee69dd3 100644
--- a/src/components/AttachmentPicker/index.native.js
+++ b/src/components/AttachmentPicker/index.native.js
@@ -14,7 +14,7 @@ import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useLocalize from '@hooks/useLocalize';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as FileUtils from '@libs/fileDownload/FileUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import {defaultProps as baseDefaultProps, propTypes as basePropTypes} from './attachmentPickerPropTypes';
import launchCamera from './launchCamera';
@@ -101,6 +101,7 @@ const getDataForUpload = (fileData) => {
* @returns {JSX.Element}
*/
function AttachmentPicker({type, children, shouldHideCameraOption}) {
+ const styles = useThemeStyles();
const [isVisible, setIsVisible] = useState(false);
const completeAttachmentSelection = useRef();
diff --git a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
index 673bb7c224e2..dd2713a38b2b 100644
--- a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
+++ b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import {PixelRatio, View} from 'react-native';
import useWindowDimensions from '@hooks/useWindowDimensions';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
const propTypes = {
/** Cell Container styles */
@@ -14,6 +14,7 @@ const defaultProps = {
};
function AttachmentCarouselCellRenderer(props) {
+ const styles = useThemeStyles();
const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
const modalStyles = styles.centeredModalStyles(isSmallScreenWidth, true);
const style = [props.style, styles.h100, {width: PixelRatio.roundToNearestPixel(windowWidth - (modalStyles.marginHorizontal + modalStyles.borderWidth) * 2)}];
diff --git a/src/components/Attachments/AttachmentCarousel/CarouselButtons.js b/src/components/Attachments/AttachmentCarousel/CarouselButtons.js
index f11bbcc9b187..14a6ea268468 100644
--- a/src/components/Attachments/AttachmentCarousel/CarouselButtons.js
+++ b/src/components/Attachments/AttachmentCarousel/CarouselButtons.js
@@ -8,8 +8,8 @@ import * as Expensicons from '@components/Icon/Expensicons';
import Tooltip from '@components/Tooltip';
import useLocalize from '@hooks/useLocalize';
import useWindowDimensions from '@hooks/useWindowDimensions';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
const propTypes = {
/** Where the arrows should be visible */
@@ -36,6 +36,8 @@ const defaultProps = {
};
function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward, cancelAutoHideArrow, autoHideArrow}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const isBackDisabled = page === 0;
const isForwardDisabled = page === _.size(attachments) - 1;
@@ -51,7 +53,7 @@ function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward
small
innerStyles={[styles.arrowIcon]}
icon={Expensicons.BackArrow}
- iconFill={themeColors.text}
+ iconFill={theme.text}
iconStyles={[styles.mr0]}
onPress={onBack}
onPressIn={cancelAutoHideArrow}
@@ -67,7 +69,7 @@ function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward
small
innerStyles={[styles.arrowIcon]}
icon={Expensicons.ArrowRight}
- iconFill={themeColors.text}
+ iconFill={theme.text}
iconStyles={[styles.mr0]}
onPress={onForward}
onPressIn={cancelAutoHideArrow}
diff --git a/src/components/Attachments/AttachmentCarousel/CarouselItem.js b/src/components/Attachments/AttachmentCarousel/CarouselItem.js
index 38f70057be61..b6cc0cbf21a4 100644
--- a/src/components/Attachments/AttachmentCarousel/CarouselItem.js
+++ b/src/components/Attachments/AttachmentCarousel/CarouselItem.js
@@ -9,7 +9,7 @@ import SafeAreaConsumer from '@components/SafeAreaConsumer';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import ReportAttachmentsContext from '@pages/home/report/ReportAttachmentsContext';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
const propTypes = {
@@ -49,6 +49,7 @@ const defaultProps = {
};
function CarouselItem({item, isFocused, onPress}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
const {isAttachmentHidden} = useContext(ReportAttachmentsContext);
// eslint-disable-next-line es/no-nullish-coalescing-operators
diff --git a/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js b/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js
index 0839462d4f23..cc1e20cb44e0 100644
--- a/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js
+++ b/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js
@@ -15,7 +15,7 @@ import Animated, {
withDecay,
withSpring,
} from 'react-native-reanimated';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import AttachmentCarouselPagerContext from './AttachmentCarouselPagerContext';
import ImageWrapper from './ImageWrapper';
@@ -60,6 +60,7 @@ const imageTransformerDefaultProps = {
};
function ImageTransformer({imageWidth, imageHeight, imageScaleX, imageScaleY, scaledImageWidth, scaledImageHeight, isActive, children}) {
+ const styles = useThemeStyles();
const {canvasWidth, canvasHeight, onTap, onSwipe, onSwipeSuccess, pagerRef, shouldPagerScroll, isScrolling, onPinchGestureChange} = useContext(AttachmentCarouselPagerContext);
const minImageScale = useMemo(() => Math.min(imageScaleX, imageScaleY), [imageScaleX, imageScaleY]);
diff --git a/src/components/Attachments/AttachmentCarousel/Pager/ImageWrapper.js b/src/components/Attachments/AttachmentCarousel/Pager/ImageWrapper.js
index 3a27d80c5509..b0a8b1f0d083 100644
--- a/src/components/Attachments/AttachmentCarousel/Pager/ImageWrapper.js
+++ b/src/components/Attachments/AttachmentCarousel/Pager/ImageWrapper.js
@@ -2,13 +2,14 @@ import PropTypes from 'prop-types';
import React from 'react';
import {StyleSheet} from 'react-native';
import Animated from 'react-native-reanimated';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
const imageWrapperPropTypes = {
children: PropTypes.node.isRequired,
};
function ImageWrapper({children}) {
+ const styles = useThemeStyles();
return (
@@ -186,7 +188,7 @@ function AttachmentView({
@@ -197,7 +199,7 @@ function AttachmentView({
diff --git a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
index c024b025c80e..27790121aab0 100644
--- a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
+++ b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
@@ -3,8 +3,8 @@ import React, {useEffect, useRef} from 'react';
import {FlatList} from 'react-native-gesture-handler';
import Animated, {Easing, FadeOutDown, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import {propTypes} from './autoCompleteSuggestionsPropTypes';
@@ -29,6 +29,7 @@ const measureHeightOfSuggestionRows = (numRows, isSuggestionPickerLarge) => {
};
function BaseAutoCompleteSuggestions(props) {
+ const styles = useThemeStyles();
const rowHeight = useSharedValue(0);
const scrollRef = useRef(null);
/**
diff --git a/src/components/AutoEmailLink.js b/src/components/AutoEmailLink.js
index eece1a16ca5a..bffd2493aa5d 100644
--- a/src/components/AutoEmailLink.js
+++ b/src/components/AutoEmailLink.js
@@ -2,7 +2,7 @@ import {CONST} from 'expensify-common/lib/CONST';
import PropTypes from 'prop-types';
import React from 'react';
import _ from 'underscore';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import Text from './Text';
import TextLink from './TextLink';
@@ -22,6 +22,7 @@ const defaultProps = {
*/
function AutoEmailLink(props) {
+ const styles = useThemeStyles();
return (
{_.map(props.text.split(CONST.REG_EXP.EXTRACT_EMAIL), (str, index) => {
diff --git a/src/components/AutoUpdateTime.js b/src/components/AutoUpdateTime.js
index c85f14ed2c29..1970839ec320 100644
--- a/src/components/AutoUpdateTime.js
+++ b/src/components/AutoUpdateTime.js
@@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
import DateUtils from '@libs/DateUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import Text from './Text';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
@@ -23,6 +23,7 @@ const propTypes = {
};
function AutoUpdateTime(props) {
+ const styles = useThemeStyles();
/**
* @returns {Date} Returns the locale Date object
*/
diff --git a/src/components/Avatar.js b/src/components/Avatar.js
index ee42f0c03e30..d7f4562ed0cf 100644
--- a/src/components/Avatar.js
+++ b/src/components/Avatar.js
@@ -5,9 +5,9 @@ import _ from 'underscore';
import useNetwork from '@hooks/useNetwork';
import * as ReportUtils from '@libs/ReportUtils';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
@@ -67,6 +67,8 @@ const defaultProps = {
};
function Avatar(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const [imageError, setImageError] = useState(false);
useNetwork({onReconnect: () => setImageError(false)});
@@ -102,11 +104,11 @@ function Avatar(props) {
src={imageError ? fallbackAvatar : props.source}
height={iconSize}
width={iconSize}
- fill={imageError ? themeColors.offline : iconFillColor}
+ fill={imageError ? theme.offline : iconFillColor}
additionalStyles={[
StyleUtils.getAvatarBorderStyle(props.size, props.type),
isWorkspace ? StyleUtils.getDefaultWorkspaceAvatarColor(props.name) : {},
- imageError ? StyleUtils.getBackgroundColorStyle(themeColors.fallbackIconColor) : {},
+ imageError ? StyleUtils.getBackgroundColorStyle(theme.fallbackIconColor) : {},
...props.iconAdditionalStyles,
]}
/>
diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js
index 106ca5750a22..3d48e5d447cd 100644
--- a/src/components/AvatarCropModal/AvatarCropModal.js
+++ b/src/components/AvatarCropModal/AvatarCropModal.js
@@ -18,9 +18,9 @@ import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
import compose from '@libs/compose';
import cropOrRotateImage from '@libs/cropOrRotateImage';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ImageCropView from './ImageCropView';
import Slider from './Slider';
@@ -62,6 +62,8 @@ const defaultProps = {
// This component can't be written using class since reanimated API uses hooks.
function AvatarCropModal(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const originalImageWidth = useSharedValue(CONST.AVATAR_CROP_MODAL.INITIAL_SIZE);
const originalImageHeight = useSharedValue(CONST.AVATAR_CROP_MODAL.INITIAL_SIZE);
const translateY = useSharedValue(0);
@@ -382,7 +384,7 @@ function AvatarCropModal(props) {
{/* To avoid layout shift we should hide this component until the image container & image is initialized */}
{!isImageInitialized || !isImageContainerInitialized ? (
@@ -403,8 +405,9 @@ function AvatarCropModal(props) {
+
diff --git a/src/components/AvatarCropModal/ImageCropView.js b/src/components/AvatarCropModal/ImageCropView.js
index 606eba0a8aea..2965ed92a284 100644
--- a/src/components/AvatarCropModal/ImageCropView.js
+++ b/src/components/AvatarCropModal/ImageCropView.js
@@ -6,9 +6,9 @@ import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import ControlSelection from '@libs/ControlSelection';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import gestureHandlerPropTypes from './gestureHandlerPropTypes';
const propTypes = {
@@ -51,6 +51,8 @@ const defaultProps = {
};
function ImageCropView(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const containerStyle = StyleUtils.getWidthAndHeightStyle(props.containerSize, props.containerSize);
const originalImageHeight = props.originalImageHeight;
@@ -87,7 +89,7 @@ function ImageCropView(props) {
diff --git a/src/components/AvatarCropModal/Slider.js b/src/components/AvatarCropModal/Slider.js
index 4281da1e7b99..9df6ac3c0498 100644
--- a/src/components/AvatarCropModal/Slider.js
+++ b/src/components/AvatarCropModal/Slider.js
@@ -6,7 +6,7 @@ import Animated, {useAnimatedStyle} from 'react-native-reanimated';
import Tooltip from '@components/Tooltip';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import ControlSelection from '@libs/ControlSelection';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import gestureHandlerPropTypes from './gestureHandlerPropTypes';
const propTypes = {
@@ -26,6 +26,7 @@ const defaultProps = {
// This component can't be written using class since reanimated API uses hooks.
function Slider(props) {
+ const styles = useThemeStyles();
const sliderValue = props.sliderValue;
const [tooltipIsVisible, setTooltipIsVisible] = useState(true);
diff --git a/src/components/AvatarSkeleton.js b/src/components/AvatarSkeleton.js
index 2a633833f228..d2706447f756 100644
--- a/src/components/AvatarSkeleton.js
+++ b/src/components/AvatarSkeleton.js
@@ -1,15 +1,16 @@
import React from 'react';
import {Circle} from 'react-native-svg';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
import SkeletonViewContentLoader from './SkeletonViewContentLoader';
function AvatarSkeleton() {
+ const theme = useTheme();
return (
{
};
function AvatarWithDisplayName(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const title = ReportUtils.getReportName(props.report);
const subtitle = ReportUtils.getChatRoomSubtitle(props.report);
const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(props.report);
@@ -99,7 +101,7 @@ function AvatarWithDisplayName(props) {
const shouldShowSubscriptAvatar = ReportUtils.shouldReportShowSubscript(props.report);
const isExpenseRequest = ReportUtils.isExpenseRequest(props.report);
const defaultSubscriptSize = isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : props.size;
- const avatarBorderColor = props.isAnonymous ? themeColors.highlightBG : themeColors.componentBG;
+ const avatarBorderColor = props.isAnonymous ? theme.highlightBG : theme.componentBG;
const headerView = (
diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js
index ac03a2f5fbcf..d2d0aa248472 100644
--- a/src/components/AvatarWithImagePicker.js
+++ b/src/components/AvatarWithImagePicker.js
@@ -9,8 +9,6 @@ import * as FileUtils from '@libs/fileDownload/FileUtils';
import getImageResolution from '@libs/fileDownload/getImageResolution';
import SpinningIndicatorAnimation from '@styles/animation/SpinningIndicatorAnimation';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import AttachmentModal from './AttachmentModal';
@@ -27,6 +25,8 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import Tooltip from './Tooltip/PopoverAnchorTooltip';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import withNavigationFocus from './withNavigationFocus';
+import withTheme, {withThemePropTypes} from './withTheme';
+import withThemeStyles, {withThemeStylesPropTypes} from './withThemeStyles';
const propTypes = {
/** Avatar source to display */
@@ -96,6 +96,8 @@ const propTypes = {
isFocused: PropTypes.bool.isRequired,
...withLocalizePropTypes,
+ ...withThemeStylesPropTypes,
+ ...withThemePropTypes,
};
const defaultProps = {
@@ -254,8 +256,8 @@ class AvatarWithImagePicker extends React.Component {
const additionalStyles = _.isArray(this.props.style) ? this.props.style : [this.props.style];
return (
-
-
+
+
{this.props.source ? (
)}
-
+
@@ -365,7 +367,7 @@ class AvatarWithImagePicker extends React.Component {
{this.state.validationError && (
@@ -387,4 +389,4 @@ class AvatarWithImagePicker extends React.Component {
AvatarWithImagePicker.propTypes = propTypes;
AvatarWithImagePicker.defaultProps = defaultProps;
-export default compose(withLocalize, withNavigationFocus)(AvatarWithImagePicker);
+export default compose(withLocalize, withNavigationFocus, withThemeStyles, withTheme)(AvatarWithImagePicker);
diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js
index 264c5ed74157..eedc66e8f327 100644
--- a/src/components/AvatarWithIndicator.js
+++ b/src/components/AvatarWithIndicator.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import * as UserUtils from '@libs/UserUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import Avatar from './Avatar';
import AvatarSkeleton from './AvatarSkeleton';
import * as Expensicons from './Icon/Expensicons';
@@ -31,6 +31,7 @@ const defaultProps = {
};
function AvatarWithIndicator(props) {
+ const styles = useThemeStyles();
return (
diff --git a/src/components/Badge.js b/src/components/Badge.js
deleted file mode 100644
index 49b330ae37b2..000000000000
--- a/src/components/Badge.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {View} from 'react-native';
-import styles from '@styles/styles';
-import * as StyleUtils from '@styles/StyleUtils';
-import CONST from '@src/CONST';
-import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
-import Text from './Text';
-
-const propTypes = {
- /** Is Success type */
- success: PropTypes.bool,
-
- /** Is Error type */
- error: PropTypes.bool,
-
- /** Whether badge is clickable */
- pressable: PropTypes.bool,
-
- /** Text to display in the Badge */
- text: PropTypes.string.isRequired,
-
- /** Text to display in the Badge */
- environment: PropTypes.string,
-
- /** Styles for Badge */
- // eslint-disable-next-line react/forbid-prop-types
- badgeStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Styles for Badge Text */
- // eslint-disable-next-line react/forbid-prop-types
- textStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Callback to be called on onPress */
- onPress: PropTypes.func,
-};
-
-const defaultProps = {
- success: false,
- error: false,
- pressable: false,
- badgeStyles: [],
- textStyles: [],
- onPress: undefined,
- environment: CONST.ENVIRONMENT.DEV,
-};
-
-function Badge(props) {
- const textStyles = props.success || props.error ? styles.textWhite : undefined;
- const Wrapper = props.pressable ? PressableWithoutFeedback : View;
- const wrapperStyles = ({pressed}) => [
- styles.badge,
- styles.ml2,
- StyleUtils.getBadgeColorStyle(props.success, props.error, pressed, props.environment === CONST.ENVIRONMENT.ADHOC),
- ...props.badgeStyles,
- ];
-
- return (
-
-
- {props.text}
-
-
- );
-}
-
-Badge.displayName = 'Badge';
-Badge.propTypes = propTypes;
-Badge.defaultProps = defaultProps;
-export default Badge;
diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx
new file mode 100644
index 000000000000..22c056dfdfc4
--- /dev/null
+++ b/src/components/Badge.tsx
@@ -0,0 +1,66 @@
+import React, {useCallback} from 'react';
+import {GestureResponderEvent, PressableStateCallbackType, StyleProp, TextStyle, View, ViewStyle} from 'react-native';
+import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
+import CONST from '@src/CONST';
+import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
+import Text from './Text';
+
+type BadgeProps = {
+ /** Is Success type */
+ success?: boolean;
+
+ /** Is Error type */
+ error?: boolean;
+
+ /** Whether badge is clickable */
+ pressable?: boolean;
+
+ /** Text to display in the Badge */
+ text: string;
+
+ /** Text to display in the Badge */
+ environment?: string;
+
+ /** Styles for Badge */
+ badgeStyles?: StyleProp;
+
+ /** Styles for Badge Text */
+ textStyles?: StyleProp;
+
+ /** Callback to be called on onPress */
+ onPress: (event?: GestureResponderEvent | KeyboardEvent) => void;
+};
+
+function Badge({success = false, error = false, pressable = false, text, environment = CONST.ENVIRONMENT.DEV, badgeStyles, textStyles, onPress = () => {}}: BadgeProps) {
+ const styles = useThemeStyles();
+ const textColorStyles = success || error ? styles.textWhite : undefined;
+ const Wrapper = pressable ? PressableWithoutFeedback : View;
+
+ const wrapperStyles: (state: PressableStateCallbackType) => StyleProp = useCallback(
+ ({pressed}) => [styles.badge, styles.ml2, StyleUtils.getBadgeColorStyle(success, error, pressed, environment === CONST.ENVIRONMENT.ADHOC), badgeStyles],
+ [styles.badge, styles.ml2, success, error, environment, badgeStyles],
+ );
+
+ return (
+
+
+ {text}
+
+
+ );
+}
+
+Badge.displayName = 'Badge';
+
+export default Badge;
diff --git a/src/components/Banner.js b/src/components/Banner.js
index f74be0fb1356..62581f17d056 100644
--- a/src/components/Banner.js
+++ b/src/components/Banner.js
@@ -3,9 +3,9 @@ import React, {memo} from 'react';
import {View} from 'react-native';
import compose from '@libs/compose';
import getButtonState from '@libs/getButtonState';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import Hoverable from './Hoverable';
import Icon from './Icon';
@@ -57,6 +57,8 @@ const defaultProps = {
};
function Banner(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
return (
{(isHovered) => {
@@ -104,7 +106,7 @@ function Banner(props) {
>
diff --git a/src/components/BaseMiniContextMenuItem.js b/src/components/BaseMiniContextMenuItem.js
index b8d7a4a7484b..04a569ba7f36 100644
--- a/src/components/BaseMiniContextMenuItem.js
+++ b/src/components/BaseMiniContextMenuItem.js
@@ -5,8 +5,8 @@ import _ from 'underscore';
import DomUtils from '@libs/DomUtils';
import getButtonState from '@libs/getButtonState';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import Tooltip from './Tooltip/PopoverAnchorTooltip';
@@ -50,6 +50,7 @@ const defaultProps = {
* @returns {JSX.Element}
*/
function BaseMiniContextMenuItem(props) {
+ const styles = useThemeStyles();
return (
diff --git a/src/components/BlockingViews/FullPageNotFoundView.js b/src/components/BlockingViews/FullPageNotFoundView.js
index 5232b5eca8dd..b82474aa0694 100644
--- a/src/components/BlockingViews/FullPageNotFoundView.js
+++ b/src/components/BlockingViews/FullPageNotFoundView.js
@@ -5,7 +5,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Illustrations from '@components/Icon/Illustrations';
import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import ROUTES from '@src/ROUTES';
import BlockingView from './BlockingView';
@@ -53,6 +53,7 @@ const defaultProps = {
// eslint-disable-next-line rulesdir/no-negated-variables
function FullPageNotFoundView({children, shouldShow, titleKey, subtitleKey, linkKey, onBackButtonPress, shouldShowLink, shouldShowBackButton, onLinkPress}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
if (shouldShow) {
return (
diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index b2b551a0db3f..5f0df5655a61 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -11,9 +11,9 @@ import Text from '@components/Text';
import withNavigationFallback from '@components/withNavigationFallback';
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import HapticFeedback from '@libs/HapticFeedback';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import validateSubmitShortcut from './validateSubmitShortcut';
@@ -128,7 +128,7 @@ const defaultProps = {
shouldShowRightIcon: false,
icon: null,
iconRight: Expensicons.ArrowRight,
- iconFill: themeColors.textLight,
+ iconFill: undefined,
iconStyles: [],
iconRightStyles: [],
isLoading: false,
@@ -202,6 +202,8 @@ function Button({
accessibilityLabel,
forwardedRef,
}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const isFocused = useIsFocused();
const keyboardShortcutCallback = useCallback(
@@ -255,7 +257,7 @@ function Button({
@@ -266,7 +268,7 @@ function Button({
@@ -335,7 +337,7 @@ function Button({
{renderContent()}
{isLoading && (
)}
diff --git a/src/components/ButtonWithDropdownMenu.js b/src/components/ButtonWithDropdownMenu.js
index 7c88d9202b78..15f2e2f4d6de 100644
--- a/src/components/ButtonWithDropdownMenu.js
+++ b/src/components/ButtonWithDropdownMenu.js
@@ -3,9 +3,9 @@ import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import useWindowDimensions from '@hooks/useWindowDimensions';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import Button from './Button';
import Icon from './Icon';
@@ -72,6 +72,8 @@ const defaultProps = {
};
function ButtonWithDropdownMenu(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const [selectedItemIndex, setSelectedItemIndex] = useState(0);
const [isMenuVisible, setIsMenuVisible] = useState(false);
const [popoverAnchorPosition, setPopoverAnchorPosition] = useState(null);
@@ -134,7 +136,7 @@ function ButtonWithDropdownMenu(props) {
diff --git a/src/components/CardPreview.js b/src/components/CardPreview.js
index 405231ff26b1..fb2571cf9a1c 100644
--- a/src/components/CardPreview.js
+++ b/src/components/CardPreview.js
@@ -4,7 +4,7 @@ import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import ExpensifyCardImage from '@assets/images/expensify-card.svg';
import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import ONYXKEYS from '@src/ONYXKEYS';
import ImageSVG from './ImageSVG';
@@ -34,6 +34,7 @@ const defaultProps = {
};
function CardPreview({privatePersonalDetails: {legalFirstName, legalLastName}, session: {email}}) {
+ const styles = useThemeStyles();
usePrivatePersonalDetails();
const cardHolder = legalFirstName && legalLastName ? `${legalFirstName} ${legalLastName}` : email;
diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js
index 156007aea76e..ff7087df91dd 100644
--- a/src/components/CategoryPicker/index.js
+++ b/src/components/CategoryPicker/index.js
@@ -5,12 +5,13 @@ import _ from 'underscore';
import OptionsSelector from '@components/OptionsSelector';
import useLocalize from '@hooks/useLocalize';
import * as OptionsListUtils from '@libs/OptionsListUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {defaultProps, propTypes} from './categoryPickerPropTypes';
function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedCategories, onSubmit}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
const [searchValue, setSearchValue] = useState('');
diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js
index 5734ad2fed26..4b9ce922aacb 100644
--- a/src/components/Checkbox.js
+++ b/src/components/Checkbox.js
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
@@ -67,6 +67,8 @@ const defaultProps = {
};
function Checkbox(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const handleSpaceKey = (event) => {
if (event.code !== 'Space') {
return;
@@ -115,7 +117,7 @@ function Checkbox(props) {
{props.isChecked && (
diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js
index 86dba1d2a932..0a90a9be46e2 100644
--- a/src/components/CheckboxWithLabel.js
+++ b/src/components/CheckboxWithLabel.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, {useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import Checkbox from './Checkbox';
import FormHelpMessage from './FormHelpMessage';
@@ -83,6 +83,7 @@ const defaultProps = {
};
function CheckboxWithLabel(props) {
+ const styles = useThemeStyles();
// We need to pick the first value that is strictly a boolean
// https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
const [isChecked, setIsChecked] = useState(() => _.find([props.value, props.defaultValue, props.isChecked], (value) => _.isBoolean(value)));
diff --git a/src/components/CommunicationsLink.js b/src/components/CommunicationsLink.js
index f09fecea5239..dbbe5737b3aa 100644
--- a/src/components/CommunicationsLink.js
+++ b/src/components/CommunicationsLink.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import Clipboard from '@libs/Clipboard';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import ContextMenuItem from './ContextMenuItem';
import * as Expensicons from './Icon/Expensicons';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
@@ -26,6 +26,7 @@ const defaultProps = {
};
function CommunicationsLink(props) {
+ const styles = useThemeStyles();
return (
diff --git a/src/components/Composer/index.js b/src/components/Composer/index.js
index d02fdd2563b1..4c61a5b5bba5 100755
--- a/src/components/Composer/index.js
+++ b/src/components/Composer/index.js
@@ -16,9 +16,9 @@ import updateIsFullComposerAvailable from '@libs/ComposerUtils/updateIsFullCompo
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
const propTypes = {
@@ -57,7 +57,7 @@ const propTypes = {
isDisabled: PropTypes.bool,
/** Set focus to this component the first time it renders.
- Override this in case you need to set focus on one field out of many, or when you want to disable autoFocus */
+ Override this in case you need to set focus on one field out of many, or when you want to disable autoFocus */
autoFocus: PropTypes.bool,
/** Update selection position on change */
@@ -169,6 +169,8 @@ function Composer({
isComposerFullSize,
...props
}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const {windowWidth} = useWindowDimensions();
const textRef = useRef(null);
const textInput = useRef(null);
@@ -448,7 +450,8 @@ function Composer({
StyleUtils.getComposeTextAreaPadding(numberOfLines, isComposerFullSize),
Browser.isMobileSafari() || Browser.isSafari() ? styles.rtlTextRenderForSafari : {},
],
- [style, maxLines, numberOfLines, isComposerFullSize],
+
+ [numberOfLines, maxLines, styles.overflowHidden, styles.rtlTextRenderForSafari, style, isComposerFullSize],
);
return (
@@ -456,7 +459,7 @@ function Composer({
(textInput.current = el)}
selection={selection}
style={inputStyleMemo}
diff --git a/src/components/ConfirmContent.js b/src/components/ConfirmContent.js
index 95ab2e3939f5..8832adf4eb90 100644
--- a/src/components/ConfirmContent.js
+++ b/src/components/ConfirmContent.js
@@ -4,8 +4,8 @@ import {View} from 'react-native';
import _ from 'underscore';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import Button from './Button';
import Header from './Header';
@@ -89,6 +89,8 @@ const defaultProps = {
};
function ConfirmContent(props) {
+ const styles = useThemeStyles();
+ const theme = useTheme();
const {translate} = useLocalize();
const {isOffline} = useNetwork();
@@ -102,7 +104,7 @@ function ConfirmContent(props) {
diff --git a/src/components/ConnectBankAccountButton.js b/src/components/ConnectBankAccountButton.js
index 2c66bcc200da..6afd3d57d4e6 100644
--- a/src/components/ConnectBankAccountButton.js
+++ b/src/components/ConnectBankAccountButton.js
@@ -3,7 +3,7 @@ import React from 'react';
import {View} from 'react-native';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import * as ReimbursementAccount from '@userActions/ReimbursementAccount';
import Button from './Button';
import * as Expensicons from './Icon/Expensicons';
@@ -30,6 +30,7 @@ const defaultProps = {
};
function ConnectBankAccountButton(props) {
+ const styles = useThemeStyles();
const activeRoute = Navigation.getActiveRouteWithoutParams();
return props.network.isOffline ? (
diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.js
index ccb1759c69cb..7f45f921fbe8 100644
--- a/src/components/ContextMenuItem.js
+++ b/src/components/ContextMenuItem.js
@@ -4,8 +4,8 @@ import useThrottledButtonState from '@hooks/useThrottledButtonState';
import useWindowDimensions from '@hooks/useWindowDimensions';
import getButtonState from '@libs/getButtonState';
import getContextMenuItemStyles from '@styles/getContextMenuItemStyles';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import BaseMiniContextMenuItem from './BaseMiniContextMenuItem';
import Icon from './Icon';
import sourcePropTypes from './Image/sourcePropTypes';
@@ -54,6 +54,7 @@ const defaultProps = {
};
function ContextMenuItem({onPress, successIcon, successText, icon, text, isMini, description, isAnonymousAction, isFocused, innerRef}) {
+ const styles = useThemeStyles();
const {windowWidth} = useWindowDimensions();
const [isThrottledButtonActive, setThrottledButtonInactive] = useThrottledButtonState();
diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js
index c2426c5b7b0b..13fc215f1d8c 100644
--- a/src/components/CountrySelector.js
+++ b/src/components/CountrySelector.js
@@ -3,7 +3,7 @@ import React, {useEffect} from 'react';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import ROUTES from '@src/ROUTES';
import FormHelpMessage from './FormHelpMessage';
import MenuItemWithTopDescription from './MenuItemWithTopDescription';
@@ -33,6 +33,7 @@ const defaultProps = {
};
function CountrySelector({errorText, value: countryCode, onInputChange, forwardedRef}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
const title = countryCode ? translate(`allCountries.${countryCode}`) : '';
diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js
index ca7816a9f117..4d43ec3d93e0 100644
--- a/src/components/CurrencySymbolButton.js
+++ b/src/components/CurrencySymbolButton.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import useLocalize from '@hooks/useLocalize';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import Text from './Text';
@@ -16,6 +16,7 @@ const propTypes = {
};
function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
return (
diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx b/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx
index 3a87702b48e4..685db8031330 100644
--- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx
+++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx
@@ -3,9 +3,9 @@ import {View} from 'react-native';
import {Circle, Rect} from 'react-native-svg';
import {ValueOf} from 'type-fest';
import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
@@ -23,12 +23,9 @@ type CurrentUserPersonalDetailsSkeletonViewProps = {
foregroundColor?: string;
};
-function CurrentUserPersonalDetailsSkeletonView({
- shouldAnimate = true,
- avatarSize = CONST.AVATAR_SIZE.LARGE,
- backgroundColor = themeColors.highlightBG,
- foregroundColor = themeColors.border,
-}: CurrentUserPersonalDetailsSkeletonViewProps) {
+function CurrentUserPersonalDetailsSkeletonView({shouldAnimate = true, avatarSize = CONST.AVATAR_SIZE.LARGE, backgroundColor, foregroundColor}: CurrentUserPersonalDetailsSkeletonViewProps) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const avatarPlaceholderSize = StyleUtils.getAvatarSize(avatarSize);
const avatarPlaceholderRadius = avatarPlaceholderSize / 2;
const spaceBetweenAvatarAndHeadline = styles.mb3.marginBottom + styles.mt1.marginTop + (variables.lineHeightXXLarge - variables.fontSizeXLarge) / 2;
@@ -39,8 +36,8 @@ function CurrentUserPersonalDetailsSkeletonView({
{formattedBalance};
}
diff --git a/src/components/CustomStatusBar/index.js b/src/components/CustomStatusBar/index.js
index 2ffd763bf088..a724c71059ef 100644
--- a/src/components/CustomStatusBar/index.js
+++ b/src/components/CustomStatusBar/index.js
@@ -1,23 +1,24 @@
import React, {useEffect} from 'react';
import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
import StatusBar from '@libs/StatusBar';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
function CustomStatusBar() {
+ const theme = useTheme();
useEffect(() => {
Navigation.isNavigationReady().then(() => {
// Set the status bar colour depending on the current route.
// If we don't have any colour defined for a route, fall back to
// appBG color.
const currentRoute = navigationRef.getCurrentRoute();
- let currentScreenBackgroundColor = themeColors.appBG;
- if (currentRoute && 'name' in currentRoute && currentRoute.name in themeColors.PAGE_BACKGROUND_COLORS) {
- currentScreenBackgroundColor = themeColors.PAGE_BACKGROUND_COLORS[currentRoute.name];
+ let currentScreenBackgroundColor = theme.appBG;
+ if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_BACKGROUND_COLORS) {
+ currentScreenBackgroundColor = theme.PAGE_BACKGROUND_COLORS[currentRoute.name];
}
StatusBar.setBarStyle('light-content', true);
StatusBar.setBackgroundColor(currentScreenBackgroundColor);
});
- }, []);
+ }, [theme.PAGE_BACKGROUND_COLORS, theme.appBG]);
return ;
}
diff --git a/src/components/DatePicker/index.android.js b/src/components/DatePicker/index.android.js
index 17d1e2e14e71..5e7086fb78ad 100644
--- a/src/components/DatePicker/index.android.js
+++ b/src/components/DatePicker/index.android.js
@@ -3,11 +3,12 @@ import {format, parseISO} from 'date-fns';
import React, {forwardRef, useCallback, useImperativeHandle, useRef, useState} from 'react';
import {Keyboard} from 'react-native';
import TextInput from '@components/TextInput';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import {defaultProps, propTypes} from './datepickerPropTypes';
const DatePicker = forwardRef(({value, defaultValue, label, placeholder, errorText, containerStyles, disabled, onBlur, onInputChange, maxDate, minDate}, outerRef) => {
+ const styles = useThemeStyles();
const ref = useRef();
const [isPickerVisible, setIsPickerVisible] = useState(false);
diff --git a/src/components/DatePicker/index.ios.js b/src/components/DatePicker/index.ios.js
index 8b884c29b07f..44a825aa8183 100644
--- a/src/components/DatePicker/index.ios.js
+++ b/src/components/DatePicker/index.ios.js
@@ -7,12 +7,14 @@ import Popover from '@components/Popover';
import TextInput from '@components/TextInput';
import useKeyboardState from '@hooks/useKeyboardState';
import useLocalize from '@hooks/useLocalize';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import {defaultProps, propTypes} from './datepickerPropTypes';
function DatePicker({value, defaultValue, innerRef, onInputChange, preferredLocale, minDate, maxDate, label, disabled, onBlur, placeholder, containerStyles, errorText}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const dateValue = value || defaultValue;
const [isPickerVisible, setIsPickerVisible] = useState(false);
const [selectedDate, setSelectedDate] = useState(dateValue ? new Date(dateValue) : new Date());
@@ -104,12 +106,13 @@ function DatePicker({value, defaultValue, innerRef, onInputChange, preferredLoca
+
diff --git a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js
index facc67c8d0e1..289629f69af6 100644
--- a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js
+++ b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js
@@ -10,8 +10,8 @@ import TextLink from '@components/TextLink';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
@@ -33,6 +33,8 @@ const defaultProps = {
};
function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
return (
@@ -40,7 +42,7 @@ function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session
@@ -57,7 +59,7 @@ function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session
diff --git a/src/components/DisplayNames/DisplayNamesTooltipItem.tsx b/src/components/DisplayNames/DisplayNamesTooltipItem.tsx
index 8f215fefd71b..82f9c5799b78 100644
--- a/src/components/DisplayNames/DisplayNamesTooltipItem.tsx
+++ b/src/components/DisplayNames/DisplayNamesTooltipItem.tsx
@@ -3,12 +3,12 @@ import {Text as RNText, StyleProp, TextStyle} from 'react-native';
import Text from '@components/Text';
import UserDetailsTooltip from '@components/UserDetailsTooltip';
import {AvatarSource} from '@libs/UserUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
type DisplayNamesTooltipItemProps = {
index?: number;
- /** The full title of the DisplayNames component (not split up) */
+ /** The function to get a distance to shift the tooltip horizontally */
getTooltipShiftX?: (index: number) => number | undefined;
/** The Account ID for the tooltip */
@@ -40,6 +40,7 @@ function DisplayNamesTooltipItem({
textStyles = [],
childRefs = {current: []},
}: DisplayNamesTooltipItemProps) {
+ const styles = useThemeStyles();
const tooltipIndexBridge = useCallback(() => getTooltipShiftX(index), [getTooltipShiftX, index]);
return (
diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx
index 43cfab23d46f..8c8720c7c99f 100644
--- a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx
+++ b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx
@@ -2,13 +2,14 @@ import React, {Fragment, useCallback, useRef} from 'react';
import {Text as RNText, View} from 'react-native';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import DisplayNamesTooltipItem from './DisplayNamesTooltipItem';
import DisplayNamesProps from './types';
type HTMLElementWithText = HTMLElement & RNText;
function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWithTooltips, textStyles = [], numberOfLines = 1}: DisplayNamesProps) {
+ const styles = useThemeStyles();
const containerRef = useRef(null);
const childRefs = useRef([]);
const isEllipsisActive = !!containerRef.current?.offsetWidth && !!containerRef.current?.scrollWidth && containerRef.current.offsetWidth < containerRef.current.scrollWidth;
diff --git a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx
index 8779a58cf4d6..1854ebe2353d 100644
--- a/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx
+++ b/src/components/DisplayNames/DisplayNamesWithoutTooltip.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import {StyleProp, TextStyle} from 'react-native';
import Text from '@components/Text';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
type DisplayNamesWithoutTooltipProps = {
/** The full title of the DisplayNames component (not split up) */
@@ -15,6 +15,7 @@ type DisplayNamesWithoutTooltipProps = {
};
function DisplayNamesWithoutTooltip({textStyles = [], numberOfLines = 1, fullTitle = ''}: DisplayNamesWithoutTooltipProps) {
+ const styles = useThemeStyles();
return (
+
{translate('eReceipt.guaranteed')}
diff --git a/src/components/DistanceMapView/index.android.js b/src/components/DistanceMapView/index.android.js
index 358b2f483a2b..848167de653d 100644
--- a/src/components/DistanceMapView/index.android.js
+++ b/src/components/DistanceMapView/index.android.js
@@ -6,11 +6,12 @@ import * as Expensicons from '@components/Icon/Expensicons';
import MapView from '@components/MapView';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import * as distanceMapViewPropTypes from './distanceMapViewPropTypes';
function DistanceMapView(props) {
+ const styles = useThemeStyles();
const [isMapReady, setIsMapReady] = useState(false);
const {isOffline} = useNetwork();
const {translate} = useLocalize();
diff --git a/src/components/DistanceRequest/DistanceRequestFooter.js b/src/components/DistanceRequest/DistanceRequestFooter.js
index 4d4335781b72..f53fadb8ab87 100644
--- a/src/components/DistanceRequest/DistanceRequestFooter.js
+++ b/src/components/DistanceRequest/DistanceRequestFooter.js
@@ -13,8 +13,8 @@ import transactionPropTypes from '@components/transactionPropTypes';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import * as TransactionUtils from '@libs/TransactionUtils';
-import styles from '@styles/styles';
-import theme from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -55,6 +55,8 @@ const defaultProps = {
transaction: {},
};
function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navigateToWaypointEditPage}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const {isOffline} = useNetwork();
const {translate} = useLocalize();
@@ -94,7 +96,7 @@ function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navig
}),
(waypoint) => waypoint,
),
- [waypoints, lastWaypointIndex],
+ [waypoints, lastWaypointIndex, theme.icon],
);
return (
diff --git a/src/components/DistanceRequest/DistanceRequestRenderItem.js b/src/components/DistanceRequest/DistanceRequestRenderItem.js
index 0ee45febb21a..1735e244a347 100644
--- a/src/components/DistanceRequest/DistanceRequestRenderItem.js
+++ b/src/components/DistanceRequest/DistanceRequestRenderItem.js
@@ -5,7 +5,7 @@ import _ from 'underscore';
import * as Expensicons from '@components/Icon/Expensicons';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import useLocalize from '@hooks/useLocalize';
-import theme from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
const propTypes = {
/** The waypoints for the distance request */
@@ -48,6 +48,7 @@ const defaultProps = {
};
function DistanceRequestRenderItem({waypoints, item, onSecondaryInteraction, getIndex, isActive, onPress, disabled}) {
+ const theme = useTheme();
const {translate} = useLocalize();
const numberOfWaypoints = _.size(waypoints);
const lastWaypointIndex = numberOfWaypoints - 1;
diff --git a/src/components/DistanceRequest/index.js b/src/components/DistanceRequest/index.js
index e702ab111921..6fa5dfede620 100644
--- a/src/components/DistanceRequest/index.js
+++ b/src/components/DistanceRequest/index.js
@@ -19,7 +19,7 @@ import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as TransactionUtils from '@libs/TransactionUtils';
import reportPropTypes from '@pages/reportPropTypes';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import * as MapboxToken from '@userActions/MapboxToken';
import * as Transaction from '@userActions/Transaction';
@@ -65,6 +65,7 @@ const defaultProps = {
};
function DistanceRequest({transactionID, report, transaction, route, isEditingRequest, onSubmit}) {
+ const styles = useThemeStyles();
const {isOffline} = useNetwork();
const {translate} = useLocalize();
diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js
index 26e01f0eee8a..ac0ac15f437d 100644
--- a/src/components/DotIndicatorMessage.js
+++ b/src/components/DotIndicatorMessage.js
@@ -4,9 +4,9 @@ import {View} from 'react-native';
import _ from 'underscore';
import * as Localize from '@libs/Localize';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import Text from './Text';
@@ -39,6 +39,8 @@ const defaultProps = {
};
function DotIndicatorMessage(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
if (_.isEmpty(props.messages)) {
return null;
}
@@ -65,7 +67,7 @@ function DotIndicatorMessage(props) {
diff --git a/src/components/DragAndDrop/NoDropZone/index.tsx b/src/components/DragAndDrop/NoDropZone/index.tsx
index 5c914b646e0c..9f2c700b8918 100644
--- a/src/components/DragAndDrop/NoDropZone/index.tsx
+++ b/src/components/DragAndDrop/NoDropZone/index.tsx
@@ -1,10 +1,11 @@
import React, {useRef} from 'react';
import {View} from 'react-native';
import useDragAndDrop from '@hooks/useDragAndDrop';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import type NoDropZoneProps from './types';
function NoDropZone({children}: NoDropZoneProps) {
+ const styles = useThemeStyles();
const noDropZone = useRef(null);
useDragAndDrop({
diff --git a/src/components/DragAndDrop/Provider/index.tsx b/src/components/DragAndDrop/Provider/index.tsx
index fbf9ffd30e80..761c512497ac 100644
--- a/src/components/DragAndDrop/Provider/index.tsx
+++ b/src/components/DragAndDrop/Provider/index.tsx
@@ -3,7 +3,7 @@ import Str from 'expensify-common/lib/str';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import useDragAndDrop from '@hooks/useDragAndDrop';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import type {DragAndDropContextParams, DragAndDropProviderProps, SetOnDropHandlerCallback} from './types';
const DragAndDropContext = React.createContext({});
@@ -13,6 +13,7 @@ function shouldAcceptDrop(event: DragEvent): boolean {
}
function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver = () => {}}: DragAndDropProviderProps) {
+ const styles = useThemeStyles();
const dropZone = useRef(null);
const dropZoneID = useRef(Str.guid('drag-n-drop'));
diff --git a/src/components/DraggableList/index.native.tsx b/src/components/DraggableList/index.native.tsx
index d7e42a5f5525..e7ff058234b7 100644
--- a/src/components/DraggableList/index.native.tsx
+++ b/src/components/DraggableList/index.native.tsx
@@ -1,10 +1,11 @@
import React from 'react';
import DraggableFlatList from 'react-native-draggable-flatlist';
import {FlatList} from 'react-native-gesture-handler';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import type {DraggableListProps} from './types';
function DraggableList({renderClone, shouldUsePortal, ...viewProps}: DraggableListProps, ref: React.ForwardedRef>) {
+ const styles = useThemeStyles();
return (
(
}: DraggableListProps,
ref: React.ForwardedRef,
) {
+ const styles = useThemeStyles();
/**
* Function to be called when the user finishes dragging an item
* It will reorder the list and call the callback function
diff --git a/src/components/EReceipt.js b/src/components/EReceipt.js
index 7c186216a1fa..85c753c7ccb3 100644
--- a/src/components/EReceipt.js
+++ b/src/components/EReceipt.js
@@ -6,8 +6,8 @@ import useLocalize from '@hooks/useLocalize';
import * as CardUtils from '@libs/CardUtils';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import * as ReportUtils from '@libs/ReportUtils';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -30,6 +30,7 @@ const defaultProps = {
};
function EReceipt({transaction, transactionID}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
// Get receipt colorway, or default to Yellow.
diff --git a/src/components/EReceiptThumbnail.js b/src/components/EReceiptThumbnail.js
index fc69601983f8..f54e246b8b1e 100644
--- a/src/components/EReceiptThumbnail.js
+++ b/src/components/EReceiptThumbnail.js
@@ -3,8 +3,8 @@ import React, {useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import * as ReportUtils from '@libs/ReportUtils';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -42,6 +42,7 @@ function getBackgroundImage(transaction) {
}
function EReceiptThumbnail({transaction}) {
+ const styles = useThemeStyles();
// Get receipt colorway, or default to Yellow.
const {backgroundColor: primaryColor, color: secondaryColor} = StyleUtils.getEReceiptColorStyles(StyleUtils.getEReceiptColorCode(transaction));
diff --git a/src/components/EmojiPicker/CategoryShortcutBar.js b/src/components/EmojiPicker/CategoryShortcutBar.js
index 7a13572a4fca..23f1ab167a89 100644
--- a/src/components/EmojiPicker/CategoryShortcutBar.js
+++ b/src/components/EmojiPicker/CategoryShortcutBar.js
@@ -3,7 +3,7 @@ import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import sourcePropTypes from '@components/Image/sourcePropTypes';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CategoryShortcutButton from './CategoryShortcutButton';
const propTypes = {
@@ -21,6 +21,7 @@ const propTypes = {
};
function CategoryShortcutBar(props) {
+ const styles = useThemeStyles();
return (
{_.map(props.headerEmojis, (headerEmoji, i) => (
diff --git a/src/components/EmojiPicker/CategoryShortcutButton.js b/src/components/EmojiPicker/CategoryShortcutButton.js
index 95038caf06b1..3886c4a2549b 100644
--- a/src/components/EmojiPicker/CategoryShortcutButton.js
+++ b/src/components/EmojiPicker/CategoryShortcutButton.js
@@ -6,9 +6,9 @@ import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeed
import Tooltip from '@components/Tooltip';
import useLocalize from '@hooks/useLocalize';
import getButtonState from '@libs/getButtonState';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
@@ -24,6 +24,8 @@ const propTypes = {
};
function CategoryShortcutButton(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const {translate} = useLocalize();
const [isHighlighted, setIsHighlighted] = useState(false);
@@ -42,7 +44,7 @@ function CategoryShortcutButton(props) {
role={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
{
+ const styles = useThemeStyles();
const [isEmojiPickerVisible, setIsEmojiPickerVisible] = useState(false);
const [emojiPopoverAnchorPosition, setEmojiPopoverAnchorPosition] = useState({
horizontal: 0,
diff --git a/src/components/EmojiPicker/EmojiPickerButton.js b/src/components/EmojiPicker/EmojiPickerButton.js
index ddfa6b89c899..440f5e3beff1 100644
--- a/src/components/EmojiPicker/EmojiPickerButton.js
+++ b/src/components/EmojiPicker/EmojiPickerButton.js
@@ -8,8 +8,8 @@ import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withNavigationFocus from '@components/withNavigationFocus';
import compose from '@libs/compose';
import getButtonState from '@libs/getButtonState';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
const propTypes = {
@@ -32,6 +32,7 @@ const defaultProps = {
};
function EmojiPickerButton(props) {
+ const styles = useThemeStyles();
const emojiPopoverAnchor = useRef(null);
useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []);
diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
index bf0527c67768..7b4f4066593c 100644
--- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
+++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
@@ -8,8 +8,8 @@ import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import getButtonState from '@libs/getButtonState';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
import CONST from '@src/CONST';
@@ -25,6 +25,7 @@ const defaultProps = {
};
function EmojiPickerButtonDropdown(props) {
+ const styles = useThemeStyles();
const emojiPopoverAnchor = useRef(null);
useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []);
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
index 8a4653dc307e..772c32ff4a88 100644
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
@@ -15,8 +15,8 @@ import useSingleExecution from '@hooks/useSingleExecution';
import useWindowDimensions from '@hooks/useWindowDimensions';
import compose from '@libs/compose';
import * as EmojiUtils from '@libs/EmojiUtils';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -42,6 +42,7 @@ const defaultProps = {
};
function EmojiPickerMenu({preferredLocale, onEmojiSelected, preferredSkinTone, translate, frequentlyUsedEmojis}) {
+ const styles = useThemeStyles();
const emojiList = useAnimatedRef();
// eslint-disable-next-line react-hooks/exhaustive-deps
const allEmojis = useMemo(() => EmojiUtils.mergeEmojisWithFrequentlyUsedEmojis(emojis), [frequentlyUsedEmojis]);
diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem/index.js b/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
index 451e2e939a09..24f876841ff7 100644
--- a/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import Text from '@components/Text';
+import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeStyles';
import * as Browser from '@libs/Browser';
import getButtonState from '@libs/getButtonState';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
import CONST from '@src/CONST';
@@ -32,6 +32,7 @@ const propTypes = {
/** Whether the menu item should be highlighted or not */
isHighlighted: PropTypes.bool,
+ ...withThemeStylesPropTypes,
};
class EmojiPickerMenuItem extends PureComponent {
@@ -94,15 +95,15 @@ class EmojiPickerMenuItem extends PureComponent {
onBlur={this.props.onBlur}
ref={(ref) => (this.ref = ref)}
style={({pressed}) => [
- this.props.isFocused ? styles.emojiItemKeyboardHighlighted : {},
- this.state.isHovered || this.props.isHighlighted ? styles.emojiItemHighlighted : {},
+ this.props.isFocused ? this.props.themeStyles.emojiItemKeyboardHighlighted : {},
+ this.state.isHovered || this.props.isHighlighted ? this.props.themeStyles.emojiItemHighlighted : {},
Browser.isMobile() && StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
- styles.emojiItem,
+ this.props.themeStyles.emojiItem,
]}
accessibilityLabel={this.props.emoji}
role={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
- {this.props.emoji}
+ {this.props.emoji}
);
}
@@ -120,7 +121,9 @@ EmojiPickerMenuItem.defaultProps = {
// Significantly speeds up re-renders of the EmojiPickerMenu's FlatList
// by only re-rendering at most two EmojiPickerMenuItems that are highlighted/un-highlighted per user action.
-export default React.memo(
- EmojiPickerMenuItem,
- (prevProps, nextProps) => prevProps.isFocused === nextProps.isFocused && prevProps.isHighlighted === nextProps.isHighlighted && prevProps.emoji === nextProps.emoji,
+export default withThemeStyles(
+ React.memo(
+ EmojiPickerMenuItem,
+ (prevProps, nextProps) => prevProps.isFocused === nextProps.isFocused && prevProps.isHighlighted === nextProps.isHighlighted && prevProps.emoji === nextProps.emoji,
+ ),
);
diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js b/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js
index 6ebaa3391992..151fabf85be3 100644
--- a/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js
+++ b/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js
@@ -2,8 +2,8 @@ import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import Text from '@components/Text';
+import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeStyles';
import getButtonState from '@libs/getButtonState';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
import CONST from '@src/CONST';
@@ -34,6 +34,7 @@ const propTypes = {
/** Whether the emoji is highlighted by the keyboard/mouse */
isUsingKeyboardMovement: PropTypes.bool,
+ ...withThemeStylesPropTypes,
};
class EmojiPickerMenuItem extends PureComponent {
@@ -72,14 +73,14 @@ class EmojiPickerMenuItem extends PureComponent {
ref={(ref) => (this.ref = ref)}
style={({pressed}) => [
StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
- this.props.isHighlighted && this.props.isUsingKeyboardMovement ? styles.emojiItemKeyboardHighlighted : {},
- this.props.isHighlighted && !this.props.isUsingKeyboardMovement ? styles.emojiItemHighlighted : {},
- styles.emojiItem,
+ this.props.isHighlighted && this.props.isUsingKeyboardMovement ? this.props.themeStyles.emojiItemKeyboardHighlighted : {},
+ this.props.isHighlighted && !this.props.isUsingKeyboardMovement ? this.props.themeStyles.emojiItemHighlighted : {},
+ this.props.themeStyles.emojiItem,
]}
accessibilityLabel={this.props.emoji}
role={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
- {this.props.emoji}
+ {this.props.emoji}
);
}
@@ -98,8 +99,10 @@ EmojiPickerMenuItem.defaultProps = {
// Significantly speeds up re-renders of the EmojiPickerMenu's FlatList
// by only re-rendering at most two EmojiPickerMenuItems that are highlighted/un-highlighted per user action.
-export default React.memo(
- EmojiPickerMenuItem,
- (prevProps, nextProps) =>
- prevProps.isHighlighted === nextProps.isHighlighted && prevProps.emoji === nextProps.emoji && prevProps.isUsingKeyboardMovement === nextProps.isUsingKeyboardMovement,
+export default withThemeStyles(
+ React.memo(
+ EmojiPickerMenuItem,
+ (prevProps, nextProps) =>
+ prevProps.isHighlighted === nextProps.isHighlighted && prevProps.emoji === nextProps.emoji && prevProps.isUsingKeyboardMovement === nextProps.isUsingKeyboardMovement,
+ ),
);
diff --git a/src/components/EmojiPicker/EmojiSkinToneList.js b/src/components/EmojiPicker/EmojiSkinToneList.js
index 29c39c335b14..25fc9ad0836a 100644
--- a/src/components/EmojiPicker/EmojiSkinToneList.js
+++ b/src/components/EmojiPicker/EmojiSkinToneList.js
@@ -6,7 +6,7 @@ import * as Emojis from '@assets/emojis';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import Text from '@components/Text';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import EmojiPickerMenuItem from './EmojiPickerMenuItem';
import getSkinToneEmojiFromIndex from './getSkinToneEmojiFromIndex';
@@ -23,6 +23,7 @@ const propTypes = {
};
function EmojiSkinToneList(props) {
+ const styles = useThemeStyles();
const [highlightedIndex, setHighlightedIndex] = useState(null);
const [isSkinToneListVisible, setIsSkinToneListVisible] = useState(false);
diff --git a/src/components/EmojiSuggestions.tsx b/src/components/EmojiSuggestions.tsx
index 8ab20cf13ad6..bb983a680af8 100644
--- a/src/components/EmojiSuggestions.tsx
+++ b/src/components/EmojiSuggestions.tsx
@@ -3,8 +3,8 @@ import {View} from 'react-native';
import type {SimpleEmoji} from '@libs/EmojiTrie';
import * as EmojiUtils from '@libs/EmojiUtils';
import getStyledTextArray from '@libs/GetStyledTextArray';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
import Text from './Text';
@@ -42,6 +42,7 @@ type EmojiSuggestionsProps = {
const keyExtractor = (item: SimpleEmoji, index: number): string => `${item.name}+${index}}`;
function EmojiSuggestions({emojis, onSelect, prefix, isEmojiPickerLarge, preferredSkinToneIndex, highlightedEmojiIndex = 0, measureParentContainer = () => {}}: EmojiSuggestionsProps) {
+ const styles = useThemeStyles();
/**
* Render an emoji suggestion menu item component.
*/
diff --git a/src/components/EnvironmentBadge.js b/src/components/EnvironmentBadge.js
index 674eaa5c2840..f32946f8bc25 100644
--- a/src/components/EnvironmentBadge.js
+++ b/src/components/EnvironmentBadge.js
@@ -1,7 +1,7 @@
import React from 'react';
import useEnvironment from '@hooks/useEnvironment';
import * as Environment from '@libs/Environment/Environment';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import pkg from '../../package.json';
import Badge from './Badge';
@@ -14,6 +14,7 @@ const ENVIRONMENT_SHORT_FORM = {
};
function EnvironmentBadge() {
+ const styles = useThemeStyles();
const {environment} = useEnvironment();
// If we are on production, don't show any badge
diff --git a/src/components/ExceededCommentLength.js b/src/components/ExceededCommentLength.js
index 43589be566ff..6353bdf40283 100644
--- a/src/components/ExceededCommentLength.js
+++ b/src/components/ExceededCommentLength.js
@@ -4,7 +4,7 @@ import React, {useEffect, useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import * as ReportUtils from '@libs/ReportUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import Text from './Text';
@@ -26,6 +26,7 @@ const defaultProps = {
};
function ExceededCommentLength(props) {
+ const styles = useThemeStyles();
const {numberFormat, translate} = useLocalize();
const [commentLength, setCommentLength] = useState(0);
const updateCommentLength = useMemo(
diff --git a/src/components/ExpensifyWordmark.js b/src/components/ExpensifyWordmark.js
index dbfba9ada94b..ac6ac9d3ea04 100644
--- a/src/components/ExpensifyWordmark.js
+++ b/src/components/ExpensifyWordmark.js
@@ -7,8 +7,8 @@ import DevLogo from '@assets/images/expensify-logo--dev.svg';
import StagingLogo from '@assets/images/expensify-logo--staging.svg';
import ProductionLogo from '@assets/images/expensify-wordmark.svg';
import useEnvironment from '@hooks/useEnvironment';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ImageSVG from './ImageSVG';
@@ -32,6 +32,7 @@ const logoComponents = {
};
function ExpensifyWordmark(props) {
+ const styles = useThemeStyles();
const {environment} = useEnvironment();
// PascalCase is required for React components, so capitalize the const here
diff --git a/src/components/FeatureList.js b/src/components/FeatureList.js
index ee55203c8222..11d793b8a584 100644
--- a/src/components/FeatureList.js
+++ b/src/components/FeatureList.js
@@ -3,7 +3,7 @@ import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import useLocalize from '@hooks/useLocalize';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import MenuItem from './MenuItem';
import menuItemPropTypes from './menuItemPropTypes';
import Text from './Text';
@@ -20,6 +20,7 @@ const propTypes = {
};
function FeatureList({menuItems, headline, description}) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
return (
<>
diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx
index afda41f16d06..34bce2133a89 100644
--- a/src/components/FixedFooter.tsx
+++ b/src/components/FixedFooter.tsx
@@ -1,6 +1,6 @@
import React, {ReactNode} from 'react';
import {StyleProp, View, ViewStyle} from 'react-native';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
type FixedFooterProps = {
/** Children to wrap in FixedFooter. */
@@ -11,6 +11,7 @@ type FixedFooterProps = {
};
function FixedFooter({style = [], children}: FixedFooterProps) {
+ const styles = useThemeStyles();
return {children};
}
diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js
index c0e01cab2954..c49f69c336eb 100644
--- a/src/components/FloatingActionButton.js
+++ b/src/components/FloatingActionButton.js
@@ -1,14 +1,15 @@
import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import {Animated, Easing, View} from 'react-native';
-import styles from '@styles/styles';
+import compose from '@libs/compose';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
import Tooltip from './Tooltip/PopoverAnchorTooltip';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import withTheme, {withThemePropTypes} from './withTheme';
+import withThemeStyles, {withThemeStylesPropTypes} from './withThemeStyles';
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
AnimatedIcon.displayName = 'AnimatedIcon';
@@ -27,6 +28,8 @@ const propTypes = {
buttonRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
...withLocalizePropTypes,
+ ...withThemeStylesPropTypes,
+ ...withThemePropTypes,
};
const defaultProps = {
@@ -70,17 +73,17 @@ class FloatingActionButton extends PureComponent {
const backgroundColor = this.animatedValue.interpolate({
inputRange: [0, 1],
- outputRange: [themeColors.success, themeColors.buttonDefaultBG],
+ outputRange: [this.props.theme.success, this.props.theme.buttonDefaultBG],
});
const fill = this.animatedValue.interpolate({
inputRange: [0, 1],
- outputRange: [themeColors.textLight, themeColors.textDark],
+ outputRange: [this.props.theme.textLight, this.props.theme.textDark],
});
return (
-
+ {
this.fabPressable = el;
@@ -97,7 +100,7 @@ class FloatingActionButton extends PureComponent {
this.props.onPress(e);
}}
onLongPress={() => {}}
- style={[styles.floatingActionButton, StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]}
+ style={[this.props.themeStyles.floatingActionButton, StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]}
>
FloatingActionButtonWithLocalizeWithRef.displayName = 'FloatingActionButtonWithLocalizeWithRef';
-export default FloatingActionButtonWithLocalizeWithRef;
+export default compose(withThemeStyles, withTheme)(FloatingActionButtonWithLocalizeWithRef);
diff --git a/src/components/Form.js b/src/components/Form.js
index 372c7a0c5d9b..28343691ea15 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -9,7 +9,7 @@ import * as ErrorUtils from '@libs/ErrorUtils';
import * as ValidationUtils from '@libs/ValidationUtils';
import Visibility from '@libs/Visibility';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import * as FormActions from '@userActions/FormActions';
import CONST from '@src/CONST';
import FormAlertWithSubmitButton from './FormAlertWithSubmitButton';
@@ -108,6 +108,7 @@ const defaultProps = {
};
function Form(props) {
+ const styles = useThemeStyles();
const [errors, setErrors] = useState({});
const [inputValues, setInputValues] = useState(() => ({...props.draftValues}));
const formRef = useRef(null);
@@ -458,24 +459,26 @@ function Form(props) {
)}
),
+
[
- childrenWrapperWithProps,
- errors,
- formContentRef,
- formRef,
- errorMessage,
- inputRefs,
- inputValues,
- submit,
props.style,
- children,
- props.formState,
- props.footerContent,
- props.enabledWhenOffline,
- props.isSubmitActionDangerous,
props.isSubmitButtonVisible,
props.submitButtonText,
+ props.formState.errorFields,
+ props.formState.isLoading,
+ props.footerContent,
props.submitButtonStyles,
+ props.enabledWhenOffline,
+ props.isSubmitActionDangerous,
+ submit,
+ childrenWrapperWithProps,
+ children,
+ inputValues,
+ errors,
+ errorMessage,
+ styles.mh0,
+ styles.mt5,
+ styles.flex1,
],
);
diff --git a/src/components/Form/FormWrapper.js b/src/components/Form/FormWrapper.js
index f82199d0f587..4f7346a94a2d 100644
--- a/src/components/Form/FormWrapper.js
+++ b/src/components/Form/FormWrapper.js
@@ -9,7 +9,7 @@ import SafeAreaConsumer from '@components/SafeAreaConsumer';
import ScrollViewWithContext from '@components/ScrollViewWithContext';
import * as ErrorUtils from '@libs/ErrorUtils';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import errorsPropType from './errorsPropType';
const propTypes = {
@@ -81,6 +81,7 @@ const defaultProps = {
};
function FormWrapper(props) {
+ const styles = useThemeStyles();
const {
onSubmit,
children,
@@ -169,6 +170,9 @@ function FormWrapper(props) {
isSubmitButtonVisible,
onSubmit,
style,
+ styles.flex1,
+ styles.mh0,
+ styles.mt5,
submitButtonStyles,
submitButtonText,
],
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index 1ffbf0d667e2..b16a4d2a08ee 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import Button from './Button';
import FormAlertWrapper from './FormAlertWrapper';
@@ -67,6 +67,7 @@ const defaultProps = {
};
function FormAlertWithSubmitButton(props) {
+ const styles = useThemeStyles();
const buttonStyles = [_.isEmpty(props.footerContent) ? {} : styles.mb3, ...props.buttonStyles];
return (
diff --git a/src/components/FormAlertWrapper.js b/src/components/FormAlertWrapper.js
index 87304ee5dc3e..c577048c0a1b 100644
--- a/src/components/FormAlertWrapper.js
+++ b/src/components/FormAlertWrapper.js
@@ -3,7 +3,7 @@ import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import compose from '@libs/compose';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import FormHelpMessage from './FormHelpMessage';
import networkPropTypes from './networkPropTypes';
import {withNetwork} from './OnyxProvider';
@@ -51,6 +51,7 @@ const defaultProps = {
// This component takes other components as a child prop. It will then render any wrapped components as a function using "render props",
// and passes it a (bool) isOffline parameter. Child components can then use the isOffline variable to determine offline behavior.
function FormAlertWrapper(props) {
+ const styles = useThemeStyles();
let children;
if (_.isEmpty(props.message)) {
children = (
diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index 717b9d9355b6..bec02c3d51f0 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -4,8 +4,8 @@ import {View} from 'react-native';
import _ from 'underscore';
import * as Localize from '@libs/Localize';
import stylePropTypes from '@styles/stylePropTypes';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import Text from './Text';
@@ -32,6 +32,8 @@ const defaultProps = {
};
function FormHelpMessage(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
if (_.isEmpty(props.message) && _.isEmpty(props.children)) {
return null;
}
@@ -42,9 +44,10 @@ function FormHelpMessage(props) {
{props.isError && (
)}
+
{props.children || {translatedMessage}}
diff --git a/src/components/FormScrollView.tsx b/src/components/FormScrollView.tsx
index e47d75f4fb26..c2f01e1d0511 100644
--- a/src/components/FormScrollView.tsx
+++ b/src/components/FormScrollView.tsx
@@ -1,6 +1,6 @@
import React, {ForwardedRef} from 'react';
import {ScrollView, ScrollViewProps} from 'react-native';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
type FormScrollViewProps = ScrollViewProps & {
/** Form elements */
@@ -8,6 +8,7 @@ type FormScrollViewProps = ScrollViewProps & {
};
function FormScrollView({children, ...rest}: FormScrollViewProps, ref: ForwardedRef) {
+ const styles = useThemeStyles();
return (
;
};
function FullScreenLoadingIndicator({style}: FullScreenLoadingIndicatorProps) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
return (
diff --git a/src/components/GrowlNotification/GrowlNotificationContainer/index.js b/src/components/GrowlNotification/GrowlNotificationContainer/index.js
index c6614e371b6d..82672edb14c2 100644
--- a/src/components/GrowlNotification/GrowlNotificationContainer/index.js
+++ b/src/components/GrowlNotification/GrowlNotificationContainer/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import {Animated} from 'react-native';
import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import growlNotificationContainerPropTypes from './growlNotificationContainerPropTypes';
const propTypes = {
@@ -10,6 +10,7 @@ const propTypes = {
};
function GrowlNotificationContainer(props) {
+ const styles = useThemeStyles();
return (
{(insets) => (
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
index 52cbc88a6652..63973ea43e19 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
@@ -9,7 +9,7 @@ import useEnvironment from '@hooks/useEnvironment';
import Navigation from '@libs/Navigation/Navigation';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import * as Url from '@libs/Url';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import * as Link from '@userActions/Link';
import * as Session from '@userActions/Session';
import CONFIG from '@src/CONFIG';
@@ -18,6 +18,7 @@ import ROUTES from '@src/ROUTES';
import htmlRendererPropTypes from './htmlRendererPropTypes';
function AnchorRenderer(props) {
+ const styles = useThemeStyles();
const htmlAttribs = props.tnode.attributes;
const {environmentURL} = useEnvironment();
// An auth token is needed to download Expensify chat attachments
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js
index 03d3afe53d4e..e97d01808a6e 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js
@@ -3,8 +3,8 @@ import _ from 'underscore';
import Text from '@components/Text';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import editedLabelStyles from '@styles/editedLabelStyles';
-import styles from '@styles/styles';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import htmlRendererPropTypes from './htmlRendererPropTypes';
@@ -15,6 +15,8 @@ const propTypes = {
};
function EditedRenderer(props) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'style', 'tnode']);
const isPendingDelete = Boolean(props.tnode.attributes.deleted !== undefined);
return (
@@ -29,7 +31,7 @@ function EditedRenderer(props) {
// eslint-disable-next-line react/jsx-props-no-spreading
{...defaultRendererProps}
fontSize={variables.fontSizeSmall}
- color={themeColors.textSupporting}
+ color={theme.textSupporting}
style={[editedLabelStyles, isPendingDelete && styles.offlineFeedback.deleted]}
>
{props.translate('reportActionCompose.edited')}
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js
index 8461f714373b..7cbdf8d69831 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js
@@ -8,7 +8,7 @@ import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportUtils from '@libs/ReportUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
@@ -17,6 +17,7 @@ import htmlRendererPropTypes from './htmlRendererPropTypes';
const propTypes = {...htmlRendererPropTypes};
function ImageRenderer(props) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
const htmlAttribs = props.tnode.attributes;
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
index b7b7c43e7b58..a60be614d9bc 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
@@ -14,8 +14,8 @@ import Navigation from '@libs/Navigation/Navigation';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import personalDetailsPropType from '@pages/personalDetailsPropType';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
@@ -32,6 +32,7 @@ const propTypes = {
};
function MentionUserRenderer(props) {
+ const styles = useThemeStyles();
const {translate} = useLocalize();
const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'style']);
const htmlAttribAccountID = lodashGet(props.tnode.attributes, 'accountid');
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
index 8edc7baeac65..a2b01059a63c 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
@@ -7,7 +7,7 @@ import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeed
import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
import withLocalize from '@components/withLocalize';
import * as ReportUtils from '@libs/ReportUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
const propTypes = {
@@ -32,6 +32,7 @@ const defaultProps = {
};
const BasePreRenderer = forwardRef((props, ref) => {
+ const styles = useThemeStyles();
const TDefaultRenderer = props.TDefaultRenderer;
const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'onPressIn', 'onPressOut', 'onLongPress']);
const isLast = props.renderIndex === props.renderLength - 1;
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index eb9a9b2c55c0..46fe1a25c920 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -1,6 +1,6 @@
import React, {ReactElement} from 'react';
import {StyleProp, TextStyle, View} from 'react-native';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
import EnvironmentBadge from './EnvironmentBadge';
import Text from './Text';
@@ -19,6 +19,7 @@ type HeaderProps = {
};
function Header({title = '', subtitle = '', textStyles = [], shouldShowEnvironmentBadge = false}: HeaderProps) {
+ const styles = useThemeStyles();
return (
diff --git a/src/components/HeaderGap/index.desktop.js b/src/components/HeaderGap/index.desktop.js
index 02918fbe3a51..2d583881cab6 100644
--- a/src/components/HeaderGap/index.desktop.js
+++ b/src/components/HeaderGap/index.desktop.js
@@ -1,17 +1,18 @@
import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import {View} from 'react-native';
-import styles from '@styles/styles';
+import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeStyles';
const propTypes = {
/** Styles to apply to the HeaderGap */
// eslint-disable-next-line react/forbid-prop-types
styles: PropTypes.arrayOf(PropTypes.object),
+ ...withThemeStylesPropTypes,
};
class HeaderGap extends PureComponent {
render() {
- return ;
+ return ;
}
}
@@ -19,4 +20,4 @@ HeaderGap.propTypes = propTypes;
HeaderGap.defaultProps = {
styles: [],
};
-export default HeaderGap;
+export default withThemeStyles(HeaderGap);
diff --git a/src/components/HeaderPageLayout.js b/src/components/HeaderPageLayout.js
index daacf197a672..260f98d208eb 100644
--- a/src/components/HeaderPageLayout.js
+++ b/src/components/HeaderPageLayout.js
@@ -5,9 +5,9 @@ import _ from 'underscore';
import useNetwork from '@hooks/useNetwork';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import FixedFooter from './FixedFooter';
import HeaderWithBackButton from './HeaderWithBackButton';
import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
@@ -42,7 +42,7 @@ const propTypes = {
};
const defaultProps = {
- backgroundColor: themeColors.appBG,
+ backgroundColor: undefined,
header: null,
headerContainerStyles: [],
scrollViewContainerStyles: [],
@@ -51,20 +51,22 @@ const defaultProps = {
};
function HeaderPageLayout({backgroundColor, children, footer, headerContainerStyles, scrollViewContainerStyles, childrenContainerStyles, style, headerContent, ...propsToPassToHeader}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const {windowHeight, isSmallScreenWidth} = useWindowDimensions();
const {isOffline} = useNetwork();
- const appBGColor = StyleUtils.getBackgroundColorStyle(themeColors.appBG);
+ const appBGColor = StyleUtils.getBackgroundColorStyle(theme.appBG);
const {titleColor, iconFill} = useMemo(() => {
- const isColorfulBackground = backgroundColor !== themeColors.appBG;
+ const isColorfulBackground = (backgroundColor || theme.appBG) !== theme.appBG;
return {
- titleColor: isColorfulBackground ? themeColors.textColorfulBackground : undefined,
- iconFill: isColorfulBackground ? themeColors.iconColorfulBackground : undefined,
+ titleColor: isColorfulBackground ? theme.textColorfulBackground : undefined,
+ iconFill: isColorfulBackground ? theme.iconColorfulBackground : undefined,
};
- }, [backgroundColor]);
+ }, [backgroundColor, theme.appBG, theme.iconColorfulBackground, theme.textColorfulBackground]);
return (
-
+
)}
@@ -90,8 +92,8 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
contentContainerStyle={[safeAreaPaddingBottomStyle, style, scrollViewContainerStyles]}
offlineIndicatorStyle={[appBGColor]}
>
- {!Browser.isSafari() && }
-
+ {!Browser.isSafari() && }
+
{headerContent}
{children}
diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js
index 3a71d6d959b2..5fbf7d8419b5 100755
--- a/src/components/HeaderWithBackButton/index.js
+++ b/src/components/HeaderWithBackButton/index.js
@@ -14,15 +14,15 @@ import useThrottledButtonState from '@hooks/useThrottledButtonState';
import useWaitForNavigation from '@hooks/useWaitForNavigation';
import getButtonState from '@libs/getButtonState';
import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import headerWithBackButtonPropTypes from './headerWithBackButtonPropTypes';
function HeaderWithBackButton({
- iconFill = themeColors.icon,
+ iconFill = null,
guidesCallTaskID = '',
onBackButtonPress = () => Navigation.goBack(ROUTES.HOME),
onCloseButtonPress = () => Navigation.dismissModal(),
@@ -55,6 +55,8 @@ function HeaderWithBackButton({
shouldOverlay = false,
singleExecution = (func) => func,
}) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState();
const {translate} = useLocalize();
const {isKeyboardShown} = useKeyboardState();
@@ -82,7 +84,7 @@ function HeaderWithBackButton({
>
diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts
index a4aa6b13cb29..3d4f0edb1656 100644
--- a/src/components/Icon/Expensicons.ts
+++ b/src/components/Icon/Expensicons.ts
@@ -45,6 +45,7 @@ import Download from '@assets/images/download.svg';
import DragAndDrop from '@assets/images/drag-and-drop.svg';
import DragHandles from '@assets/images/drag-handles.svg';
import Emoji from '@assets/images/emoji.svg';
+import EmptyStateAttachReceipt from '@assets/images/empty-state__attach-receipt.svg';
import EmptyStateRoutePending from '@assets/images/emptystate__routepending.svg';
import EReceiptIcon from '@assets/images/eReceiptIcon.svg';
import Exclamation from '@assets/images/exclamation.svg';
@@ -176,6 +177,7 @@ export {
EReceiptIcon,
Emoji,
EmptyStateRoutePending,
+ EmptyStateAttachReceipt,
Exclamation,
Exit,
ExpensifyCard,
diff --git a/src/components/Icon/svgs/LoungeAccessIcon.tsx b/src/components/Icon/svgs/LoungeAccessIcon.tsx
index fffbe1b60451..48b140da3bc8 100644
--- a/src/components/Icon/svgs/LoungeAccessIcon.tsx
+++ b/src/components/Icon/svgs/LoungeAccessIcon.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import Svg, {G, Path, Polygon} from 'react-native-svg';
-import themeColors from '@styles/themes/default';
+import useTheme from '@styles/themes/useTheme';
type LoungeAccessIconProps = {
/** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue'. */
@@ -19,7 +19,8 @@ type LoungeAccessIconProps = {
height?: number;
};
-function LoungeAccessIcon({fill = themeColors.icon, hovered = 'false', pressed = 'false', width, height}: LoungeAccessIconProps) {
+function LoungeAccessIcon({fill, hovered = 'false', pressed = 'false', width, height}: LoungeAccessIconProps) {
+ const theme = useTheme();
return (