Upgrade Prettier
This commit is contained in:
parent
d14c8e2277
commit
0d3b390129
57 changed files with 1074 additions and 1574 deletions
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
|
@ -12,7 +12,7 @@ locations if you have a question or comment:
|
||||||
Lastly, be sure to preview your issue before saving. Thanks!
|
Lastly, be sure to preview your issue before saving. Thanks!
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* [ ] I have searched open and closed issues for duplicates
|
- [ ] I have searched open and closed issues for duplicates
|
||||||
<!--
|
<!--
|
||||||
You can search all issues here:
|
You can search all issues here:
|
||||||
https://github.com/signalapp/Signal-Desktop/issues?utf8=%E2%9C%93&q=is%3Aissue
|
https://github.com/signalapp/Signal-Desktop/issues?utf8=%E2%9C%93&q=is%3Aissue
|
||||||
|
|
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -9,16 +9,16 @@ Remember, you can preview this before saving it.
|
||||||
|
|
||||||
### First time contributor checklist:
|
### First time contributor checklist:
|
||||||
|
|
||||||
* [ ] I have read the [README](https://github.com/signalapp/Signal-Desktop/blob/master/README.md) and [Contributor Guidelines](https://github.com/signalapp/Signal-Desktop/blob/master/CONTRIBUTING.md)
|
- [ ] I have read the [README](https://github.com/signalapp/Signal-Desktop/blob/master/README.md) and [Contributor Guidelines](https://github.com/signalapp/Signal-Desktop/blob/master/CONTRIBUTING.md)
|
||||||
* [ ] I have signed the [Contributor Licence Agreement](https://signal.org/cla/)
|
- [ ] I have signed the [Contributor Licence Agreement](https://signal.org/cla/)
|
||||||
|
|
||||||
### Contributor checklist:
|
### Contributor checklist:
|
||||||
|
|
||||||
* [ ] My contribution is **not** related to translations. _Please submit translation changes via our [Signal Desktop Transifex project](https://www.transifex.com/signalapp/signal-desktop/)._
|
- [ ] My contribution is **not** related to translations. _Please submit translation changes via our [Signal Desktop Transifex project](https://www.transifex.com/signalapp/signal-desktop/)._
|
||||||
* [ ] My commits are in nice logical chunks with [good commit messages](http://chris.beams.io/posts/git-commit/)
|
- [ ] My commits are in nice logical chunks with [good commit messages](http://chris.beams.io/posts/git-commit/)
|
||||||
* [ ] My changes are [rebased](https://medium.freecodecamp.org/git-rebase-and-the-golden-rule-explained-70715eccc372) on the latest [`development`](https://github.com/signalapp/Signal-Desktop/tree/development) branch
|
- [ ] My changes are [rebased](https://medium.freecodecamp.org/git-rebase-and-the-golden-rule-explained-70715eccc372) on the latest [`development`](https://github.com/signalapp/Signal-Desktop/tree/development) branch
|
||||||
* [ ] A `yarn ready` run passes successfully ([more about tests here](https://github.com/signalapp/Signal-Desktop/blob/master/CONTRIBUTING.md#tests))
|
- [ ] A `yarn ready` run passes successfully ([more about tests here](https://github.com/signalapp/Signal-Desktop/blob/master/CONTRIBUTING.md#tests))
|
||||||
* [ ] My changes are ready to be shipped to users
|
- [ ] My changes are ready to be shipped to users
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,9 @@ Then you need `git`, if you don't have that yet: https://git-scm.com/
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
1. **Windows 7 only:**
|
1. **Windows 7 only:**
|
||||||
* Install Microsoft .NET Framework 4.5.1:
|
- Install Microsoft .NET Framework 4.5.1:
|
||||||
https://www.microsoft.com/en-us/download/details.aspx?id=40773
|
https://www.microsoft.com/en-us/download/details.aspx?id=40773
|
||||||
* Install Windows SDK version 8.1: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
|
- Install Windows SDK version 8.1: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
|
||||||
1. Install _Windows Build Tools_: Open the [Command Prompt (`cmd.exe`) as Administrator](<https://technet.microsoft.com/en-us/library/cc947813(v=ws.10).aspx>)
|
1. Install _Windows Build Tools_: Open the [Command Prompt (`cmd.exe`) as Administrator](<https://technet.microsoft.com/en-us/library/cc947813(v=ws.10).aspx>)
|
||||||
and run: `npm install --global --production --add-python-to-path windows-build-tools`
|
and run: `npm install --global --production --add-python-to-path windows-build-tools`
|
||||||
|
|
||||||
|
@ -115,9 +115,9 @@ Desktop to populate your testing application!
|
||||||
|
|
||||||
First, find your application data:
|
First, find your application data:
|
||||||
|
|
||||||
* macOS: `~/Library/Application Support/Signal`
|
- macOS: `~/Library/Application Support/Signal`
|
||||||
* Linux: `~/.config/Signal`
|
- Linux: `~/.config/Signal`
|
||||||
* Windows 10: `C:\Users\<YourName>\AppData\Roaming\Signal`
|
- Windows 10: `C:\Users\<YourName>\AppData\Roaming\Signal`
|
||||||
|
|
||||||
Now make a copy of this production data directory in the same place, and call it
|
Now make a copy of this production data directory in the same place, and call it
|
||||||
`Signal-development`. Now start up the development version of the app as normal,
|
`Signal-development`. Now start up the development version of the app as normal,
|
||||||
|
@ -189,31 +189,31 @@ the report with `yarn open-coverage`.
|
||||||
|
|
||||||
So you wanna make a pull request? Please observe the following guidelines.
|
So you wanna make a pull request? Please observe the following guidelines.
|
||||||
|
|
||||||
* First, make sure that your `yarn ready` run passes - it's very similar to what our
|
- First, make sure that your `yarn ready` run passes - it's very similar to what our
|
||||||
Continuous Integration servers do to test the app.
|
Continuous Integration servers do to test the app.
|
||||||
* Please do not submit pull requests for translation fixes. Anyone can update
|
- Please do not submit pull requests for translation fixes. Anyone can update
|
||||||
the translations in
|
the translations in
|
||||||
[Transifex](https://www.transifex.com/projects/p/signal-desktop).
|
[Transifex](https://www.transifex.com/projects/p/signal-desktop).
|
||||||
* Never use plain strings right in the source code - pull them from `messages.json`!
|
- Never use plain strings right in the source code - pull them from `messages.json`!
|
||||||
You **only** need to modify the default locale
|
You **only** need to modify the default locale
|
||||||
[`_locales/en/messages.json`](_locales/en/messages.json). Other locales are generated
|
[`_locales/en/messages.json`](_locales/en/messages.json). Other locales are generated
|
||||||
automatically based on that file and then periodically uploaded to Transifex for
|
automatically based on that file and then periodically uploaded to Transifex for
|
||||||
translation.
|
translation.
|
||||||
* [Rebase](https://nathanleclaire.com/blog/2014/09/14/dont-be-scared-of-git-rebase/) your
|
- [Rebase](https://nathanleclaire.com/blog/2014/09/14/dont-be-scared-of-git-rebase/) your
|
||||||
changes on the latest `development` branch, resolving any conflicts.
|
changes on the latest `development` branch, resolving any conflicts.
|
||||||
This ensures that your changes will merge cleanly when you open your PR.
|
This ensures that your changes will merge cleanly when you open your PR.
|
||||||
* Be sure to add and run tests!
|
- Be sure to add and run tests!
|
||||||
* Make sure the diff between our master and your branch contains only the
|
- Make sure the diff between our master and your branch contains only the
|
||||||
minimal set of changes needed to implement your feature or bugfix. This will
|
minimal set of changes needed to implement your feature or bugfix. This will
|
||||||
make it easier for the person reviewing your code to approve the changes.
|
make it easier for the person reviewing your code to approve the changes.
|
||||||
Please do not submit a PR with commented out code or unfinished features.
|
Please do not submit a PR with commented out code or unfinished features.
|
||||||
* Avoid meaningless or too-granular commits. If your branch contains commits like
|
- Avoid meaningless or too-granular commits. If your branch contains commits like
|
||||||
the lines of "Oops, reverted this change" or "Just experimenting, will
|
the lines of "Oops, reverted this change" or "Just experimenting, will
|
||||||
delete this later", please [squash or rebase those changes away](https://robots.thoughtbot.com/git-interactive-rebase-squash-amend-rewriting-history).
|
delete this later", please [squash or rebase those changes away](https://robots.thoughtbot.com/git-interactive-rebase-squash-amend-rewriting-history).
|
||||||
* Don't have too few commits. If you have a complicated or long lived feature
|
- Don't have too few commits. If you have a complicated or long lived feature
|
||||||
branch, it may make sense to break the changes up into logical atomic chunks
|
branch, it may make sense to break the changes up into logical atomic chunks
|
||||||
to aid in the review process.
|
to aid in the review process.
|
||||||
* Provide a well written and nicely formatted commit message. See [this
|
- Provide a well written and nicely formatted commit message. See [this
|
||||||
link](http://chris.beams.io/posts/git-commit/)
|
link](http://chris.beams.io/posts/git-commit/)
|
||||||
for some tips on formatting. As far as content, try to include in your
|
for some tips on formatting. As far as content, try to include in your
|
||||||
summary
|
summary
|
||||||
|
|
12
Gruntfile.js
12
Gruntfile.js
|
@ -150,18 +150,12 @@ module.exports = grunt => {
|
||||||
},
|
},
|
||||||
'test-release': {
|
'test-release': {
|
||||||
osx: {
|
osx: {
|
||||||
archive: `mac/${
|
archive: `mac/${packageJson.productName}.app/Contents/Resources/app.asar`,
|
||||||
packageJson.productName
|
exe: `mac/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`,
|
||||||
}.app/Contents/Resources/app.asar`,
|
|
||||||
exe: `mac/${packageJson.productName}.app/Contents/MacOS/${
|
|
||||||
packageJson.productName
|
|
||||||
}`,
|
|
||||||
},
|
},
|
||||||
mas: {
|
mas: {
|
||||||
archive: 'mas/Signal.app/Contents/Resources/app.asar',
|
archive: 'mas/Signal.app/Contents/Resources/app.asar',
|
||||||
exe: `mas/${packageJson.productName}.app/Contents/MacOS/${
|
exe: `mas/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`,
|
||||||
packageJson.productName
|
|
||||||
}`,
|
|
||||||
},
|
},
|
||||||
linux: {
|
linux: {
|
||||||
archive: 'linux-unpacked/resources/app.asar',
|
archive: 'linux-unpacked/resources/app.asar',
|
||||||
|
|
|
@ -13,9 +13,9 @@ or [iOS](https://github.com/signalapp/Signal-iOS).
|
||||||
|
|
||||||
You can install the beta version of Signal Desktop alongside the production version. The beta uses different data and install locations.
|
You can install the beta version of Signal Desktop alongside the production version. The beta uses different data and install locations.
|
||||||
|
|
||||||
* _Windows:_ First, download [this file](https://updates.signal.org/desktop/beta.yml) and look for the `url` property that specifies the location for the latest beta installer. Download the installer by constructing a final URL that looks like this: `https://updates.signal.org/desktop/<installer location>`. Then run the installer.
|
- _Windows:_ First, download [this file](https://updates.signal.org/desktop/beta.yml) and look for the `url` property that specifies the location for the latest beta installer. Download the installer by constructing a final URL that looks like this: `https://updates.signal.org/desktop/<installer location>`. Then run the installer.
|
||||||
* _macOS:_ First, download [this file](https://updates.signal.org/desktop/beta-mac.yml) and look for the `url` property that specifies the location for the latest beta installer. Download the installer by constructing a final URL that looks like this: `https://updates.signal.org/desktop/<package location>`. Then unzip that package and copy the `.app` file into the `/Applications` folder using Finder.
|
- _macOS:_ First, download [this file](https://updates.signal.org/desktop/beta-mac.yml) and look for the `url` property that specifies the location for the latest beta installer. Download the installer by constructing a final URL that looks like this: `https://updates.signal.org/desktop/<package location>`. Then unzip that package and copy the `.app` file into the `/Applications` folder using Finder.
|
||||||
* _Linux:_ Follow the production instructions to set up the APT repository and run `apt install signal-desktop-beta`.
|
- _Linux:_ Follow the production instructions to set up the APT repository and run `apt install signal-desktop-beta`.
|
||||||
|
|
||||||
## Got a question?
|
## Got a question?
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,9 +43,7 @@ async function initialize() {
|
||||||
try {
|
try {
|
||||||
await cleanupLogs(logPath);
|
await cleanupLogs(logPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorString = `Failed to clean logs; deleting all. Error: ${
|
const errorString = `Failed to clean logs; deleting all. Error: ${error.stack}`;
|
||||||
error.stack
|
|
||||||
}`;
|
|
||||||
console.error(errorString);
|
console.error(errorString);
|
||||||
await deleteAllLogs(logPath);
|
await deleteAllLogs(logPath);
|
||||||
mkdirp.sync(logPath);
|
mkdirp.sync(logPath);
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
"cdnUrl": "https://cdn-staging.signal.org",
|
"cdnUrl": "https://cdn-staging.signal.org",
|
||||||
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
||||||
"updatesUrl": "https://updates2.signal.org/desktop",
|
"updatesUrl": "https://updates2.signal.org/desktop",
|
||||||
"updatesPublicKey":
|
"updatesPublicKey": "fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
||||||
"fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
|
||||||
"updatesEnabled": false,
|
"updatesEnabled": false,
|
||||||
"openDevTools": false,
|
"openDevTools": false,
|
||||||
"buildExpiration": 0,
|
"buildExpiration": 0,
|
||||||
"certificateAuthority":
|
"certificateAuthority": "-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIJAIm6LatK5PNiMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\naXNjbzEdMBsGA1UECgwUT3BlbiBXaGlzcGVyIFN5c3RlbXMxHTAbBgNVBAsMFE9w\nZW4gV2hpc3BlciBTeXN0ZW1zMRMwEQYDVQQDDApUZXh0U2VjdXJlMB4XDTEzMDMy\nNTIyMTgzNVoXDTIzMDMyMzIyMTgzNVowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI\nDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMR0wGwYDVQQKDBRP\ncGVuIFdoaXNwZXIgU3lzdGVtczEdMBsGA1UECwwUT3BlbiBXaGlzcGVyIFN5c3Rl\nbXMxEzARBgNVBAMMClRleHRTZWN1cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQDBSWBpOCBDF0i4q2d4jAXkSXUGpbeWugVPQCjaL6qD9QDOxeW1afvf\nPo863i6Crq1KDxHpB36EwzVcjwLkFTIMeo7t9s1FQolAt3mErV2U0vie6Ves+yj6\ngrSfxwIDAcdsKmI0a1SQCZlr3Q1tcHAkAKFRxYNawADyps5B+Zmqcgf653TXS5/0\nIPPQLocLn8GWLwOYNnYfBvILKDMItmZTtEbucdigxEA9mfIvvHADEbteLtVgwBm9\nR5vVvtwrD6CCxI3pgH7EH7kMP0Od93wLisvn1yhHY7FuYlrkYqdkMvWUrKoASVw4\njb69vaeJCUdU+HCoXOSP1PQcL6WenNCHAgMBAAGjUDBOMB0GA1UdDgQWBBQBixjx\nP/s5GURuhYa+lGUypzI8kDAfBgNVHSMEGDAWgBQBixjxP/s5GURuhYa+lGUypzI8\nkDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQB+Hr4hC56m0LvJAu1R\nK6NuPDbTMEN7/jMojFHxH4P3XPFfupjR+bkDq0pPOU6JjIxnrD1XD/EVmTTaTVY5\niOheyv7UzJOefb2pLOc9qsuvI4fnaESh9bhzln+LXxtCrRPGhkxA1IMIo3J/s2WF\n/KVYZyciu6b4ubJ91XPAuBNZwImug7/srWvbpk0hq6A6z140WTVSKtJG7EP41kJe\n/oF4usY5J7LPkxK3LWzMJnb5EIJDmRvyH8pyRwWg6Qm6qiGFaI4nL8QU4La1x2en\n4DGXRaLMPRwjELNgQPodR38zoCMuA8gHZfZYYoZ7D7Q1wNUiVHcxuFrEeBaYJbLE\nrwLV\n-----END CERTIFICATE-----\n",
|
||||||
"-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIJAIm6LatK5PNiMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j\naXNjbzEdMBsGA1UECgwUT3BlbiBXaGlzcGVyIFN5c3RlbXMxHTAbBgNVBAsMFE9w\nZW4gV2hpc3BlciBTeXN0ZW1zMRMwEQYDVQQDDApUZXh0U2VjdXJlMB4XDTEzMDMy\nNTIyMTgzNVoXDTIzMDMyMzIyMTgzNVowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI\nDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMR0wGwYDVQQKDBRP\ncGVuIFdoaXNwZXIgU3lzdGVtczEdMBsGA1UECwwUT3BlbiBXaGlzcGVyIFN5c3Rl\nbXMxEzARBgNVBAMMClRleHRTZWN1cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQDBSWBpOCBDF0i4q2d4jAXkSXUGpbeWugVPQCjaL6qD9QDOxeW1afvf\nPo863i6Crq1KDxHpB36EwzVcjwLkFTIMeo7t9s1FQolAt3mErV2U0vie6Ves+yj6\ngrSfxwIDAcdsKmI0a1SQCZlr3Q1tcHAkAKFRxYNawADyps5B+Zmqcgf653TXS5/0\nIPPQLocLn8GWLwOYNnYfBvILKDMItmZTtEbucdigxEA9mfIvvHADEbteLtVgwBm9\nR5vVvtwrD6CCxI3pgH7EH7kMP0Od93wLisvn1yhHY7FuYlrkYqdkMvWUrKoASVw4\njb69vaeJCUdU+HCoXOSP1PQcL6WenNCHAgMBAAGjUDBOMB0GA1UdDgQWBBQBixjx\nP/s5GURuhYa+lGUypzI8kDAfBgNVHSMEGDAWgBQBixjxP/s5GURuhYa+lGUypzI8\nkDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQB+Hr4hC56m0LvJAu1R\nK6NuPDbTMEN7/jMojFHxH4P3XPFfupjR+bkDq0pPOU6JjIxnrD1XD/EVmTTaTVY5\niOheyv7UzJOefb2pLOc9qsuvI4fnaESh9bhzln+LXxtCrRPGhkxA1IMIo3J/s2WF\n/KVYZyciu6b4ubJ91XPAuBNZwImug7/srWvbpk0hq6A6z140WTVSKtJG7EP41kJe\n/oF4usY5J7LPkxK3LWzMJnb5EIJDmRvyH8pyRwWg6Qm6qiGFaI4nL8QU4La1x2en\n4DGXRaLMPRwjELNgQPodR38zoCMuA8gHZfZYYoZ7D7Q1wNUiVHcxuFrEeBaYJbLE\nrwLV\n-----END CERTIFICATE-----\n",
|
|
||||||
"import": false,
|
"import": false,
|
||||||
"serverTrustRoot": "BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx"
|
"serverTrustRoot": "BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx"
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,9 +498,7 @@
|
||||||
idleDetector = new IdleDetector();
|
idleDetector = new IdleDetector();
|
||||||
let isMigrationWithIndexComplete = false;
|
let isMigrationWithIndexComplete = false;
|
||||||
window.log.info(
|
window.log.info(
|
||||||
`Starting background data migration. Target version: ${
|
`Starting background data migration. Target version: ${Message.CURRENT_SCHEMA_VERSION}`
|
||||||
Message.CURRENT_SCHEMA_VERSION
|
|
||||||
}`
|
|
||||||
);
|
);
|
||||||
idleDetector.on('idle', async () => {
|
idleDetector.on('idle', async () => {
|
||||||
const NUM_MESSAGES_PER_BATCH = 1;
|
const NUM_MESSAGES_PER_BATCH = 1;
|
||||||
|
@ -1611,7 +1609,9 @@
|
||||||
const ourNumber = textsecure.storage.user.getNumber();
|
const ourNumber = textsecure.storage.user.getNumber();
|
||||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||||
ourNumber,
|
ourNumber,
|
||||||
{ syncMessage: true }
|
{
|
||||||
|
syncMessage: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const installedStickerPacks = window.Signal.Stickers.getInstalledStickerPacks();
|
const installedStickerPacks = window.Signal.Stickers.getInstalledStickerPacks();
|
||||||
|
|
|
@ -955,7 +955,9 @@
|
||||||
const ourNumber = textsecure.storage.user.getNumber();
|
const ourNumber = textsecure.storage.user.getNumber();
|
||||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||||
ourNumber,
|
ourNumber,
|
||||||
{ syncMessage: true }
|
{
|
||||||
|
syncMessage: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
await wrap(
|
await wrap(
|
||||||
|
@ -1480,7 +1482,9 @@
|
||||||
const ourNumber = textsecure.storage.user.getNumber();
|
const ourNumber = textsecure.storage.user.getNumber();
|
||||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||||
ourNumber,
|
ourNumber,
|
||||||
{ syncMessage: true }
|
{
|
||||||
|
syncMessage: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
this.syncPromise = this.syncPromise || Promise.resolve();
|
this.syncPromise = this.syncPromise || Promise.resolve();
|
||||||
|
|
|
@ -396,7 +396,7 @@ function getRandomValue(low, high) {
|
||||||
|
|
||||||
// Because high and low are inclusive
|
// Because high and low are inclusive
|
||||||
const mod = diff + 1;
|
const mod = diff + 1;
|
||||||
return bytes[0] % mod + low;
|
return (bytes[0] % mod) + low;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getZeroes(n) {
|
function getZeroes(n) {
|
||||||
|
@ -454,9 +454,7 @@ function splitBytes(buffer, ...lengths) {
|
||||||
|
|
||||||
if (total !== buffer.byteLength) {
|
if (total !== buffer.byteLength) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested lengths total ${total} does not match source total ${
|
`Requested lengths total ${total} does not match source total ${buffer.byteLength}`
|
||||||
buffer.byteLength
|
|
||||||
}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ function _getString(thing) {
|
||||||
return thing;
|
return thing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
function _b64ToUint6(nChr) {
|
function _b64ToUint6(nChr) {
|
||||||
return nChr > 64 && nChr < 91
|
return nChr > 64 && nChr < 91
|
||||||
? nChr - 65
|
? nChr - 65
|
||||||
|
|
|
@ -1098,9 +1098,7 @@
|
||||||
const data = await readDraftData(attachment.path);
|
const data = await readDraftData(attachment.path);
|
||||||
if (data.byteLength !== attachment.size) {
|
if (data.byteLength !== attachment.size) {
|
||||||
window.log.error(
|
window.log.error(
|
||||||
`Attachment size from disk ${
|
`Attachment size from disk ${data.byteLength} did not match attachment size ${attachment.size}`
|
||||||
data.byteLength
|
|
||||||
} did not match attachment size ${attachment.size}`
|
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1411,7 +1409,7 @@
|
||||||
blob = window.dataURLToBlobSync(
|
blob = window.dataURLToBlobSync(
|
||||||
canvas.toDataURL(targetContentType, quality)
|
canvas.toDataURL(targetContentType, quality)
|
||||||
);
|
);
|
||||||
quality = quality * maxSize / blob.size;
|
quality = (quality * maxSize) / blob.size;
|
||||||
// NOTE: During testing with a large image, we observed the
|
// NOTE: During testing with a large image, we observed the
|
||||||
// `quality` value being > 1. Should we clamp it to [0.5, 1.0]?
|
// `quality` value being > 1. Should we clamp it to [0.5, 1.0]?
|
||||||
// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Syntax
|
// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Syntax
|
||||||
|
|
|
@ -1198,9 +1198,7 @@ MessageReceiver.prototype.extend({
|
||||||
|
|
||||||
if (!_.isNumber(size)) {
|
if (!_.isNumber(size)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`downloadAttachment: Size was not provided, actual size was ${
|
`downloadAttachment: Size was not provided, actual size was ${data.byteLength}`
|
||||||
data.byteLength
|
|
||||||
}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1251,11 +1249,7 @@ MessageReceiver.prototype.extend({
|
||||||
|
|
||||||
if (envelopeTimestamp !== decryptedTimestamp) {
|
if (envelopeTimestamp !== decryptedTimestamp) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Timestamp ${
|
`Timestamp ${decrypted.timestamp} in DataMessage did not match envelope timestamp ${envelope.timestamp}`
|
||||||
decrypted.timestamp
|
|
||||||
} in DataMessage did not match envelope timestamp ${
|
|
||||||
envelope.timestamp
|
|
||||||
}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ OutgoingMessage.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.catch(e => {
|
return promise.catch(e => {
|
||||||
if (e.name === 'HTTPError' && (e.code !== 409 && e.code !== 410)) {
|
if (e.name === 'HTTPError' && e.code !== 409 && e.code !== 410) {
|
||||||
// 409 and 410 should bubble and be handled by doSendMessage
|
// 409 and 410 should bubble and be handled by doSendMessage
|
||||||
// 404 should throw UnregisteredUserError
|
// 404 should throw UnregisteredUserError
|
||||||
// all other network errors can be retried later.
|
// all other network errors can be retried later.
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
}
|
}
|
||||||
const protos = result.build('signalservice');
|
const protos = result.build('signalservice');
|
||||||
if (!protos) {
|
if (!protos) {
|
||||||
const text = `Error loading protos from ${filename} (root: ${
|
const text = `Error loading protos from ${filename} (root: ${window.PROTO_ROOT})`;
|
||||||
window.PROTO_ROOT
|
|
||||||
})`;
|
|
||||||
window.log.error(text);
|
window.log.error(text);
|
||||||
throw new Error(text);
|
throw new Error(text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,9 +209,7 @@ MessageSender.prototype = {
|
||||||
}
|
}
|
||||||
if (data.byteLength !== size) {
|
if (data.byteLength !== size) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`makeAttachmentPointer: Size ${size} did not match data.byteLength ${
|
`makeAttachmentPointer: Size ${size} did not match data.byteLength ${data.byteLength}`
|
||||||
data.byteLength
|
|
||||||
}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
* https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses
|
* https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
b64ToUint6(nChr) {
|
b64ToUint6(nChr) {
|
||||||
return nChr > 64 && nChr < 91
|
return nChr > 64 && nChr < 91
|
||||||
? nChr - 65
|
? nChr - 65
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
return aBBytes;
|
return aBBytes;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
uint6ToB64(nUint6) {
|
uint6ToB64(nUint6) {
|
||||||
return nUint6 < 26
|
return nUint6 < 26
|
||||||
? nUint6 + 65
|
? nUint6 + 65
|
||||||
|
@ -82,7 +84,7 @@
|
||||||
nIdx += 1
|
nIdx += 1
|
||||||
) {
|
) {
|
||||||
nMod3 = nIdx % 3;
|
nMod3 = nIdx % 3;
|
||||||
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) {
|
if (nIdx > 0 && ((nIdx * 4) / 3) % 76 === 0) {
|
||||||
sB64Enc += '\r\n';
|
sB64Enc += '\r\n';
|
||||||
}
|
}
|
||||||
nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24);
|
nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24);
|
||||||
|
|
|
@ -24,10 +24,10 @@
|
||||||
receiver.addEventListener('groupsync', this.ongroup);
|
receiver.addEventListener('groupsync', this.ongroup);
|
||||||
|
|
||||||
const ourNumber = textsecure.storage.user.getNumber();
|
const ourNumber = textsecure.storage.user.getNumber();
|
||||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
const {
|
||||||
ourNumber,
|
wrap,
|
||||||
{ syncMessage: true }
|
sendOptions,
|
||||||
);
|
} = ConversationController.prepareForSend(ourNumber, { syncMessage: true });
|
||||||
|
|
||||||
window.log.info('SyncRequest created. Sending config sync request...');
|
window.log.info('SyncRequest created. Sending config sync request...');
|
||||||
wrap(sender.sendRequestConfigurationSyncMessage(sendOptions));
|
wrap(sender.sendRequestConfigurationSyncMessage(sendOptions));
|
||||||
|
|
2
main.js
2
main.js
|
@ -578,7 +578,7 @@ async function getIsLinked() {
|
||||||
|
|
||||||
let stickerCreatorWindow;
|
let stickerCreatorWindow;
|
||||||
async function showStickerCreator() {
|
async function showStickerCreator() {
|
||||||
if (!await getIsLinked()) {
|
if (!(await getIsLinked())) {
|
||||||
const { message } = locale.messages[
|
const { message } = locale.messages[
|
||||||
'StickerCreator--Authentication--error'
|
'StickerCreator--Authentication--error'
|
||||||
];
|
];
|
||||||
|
|
|
@ -224,7 +224,7 @@
|
||||||
"npm-run-all": "4.1.5",
|
"npm-run-all": "4.1.5",
|
||||||
"nyc": "11.4.1",
|
"nyc": "11.4.1",
|
||||||
"patch-package": "6.1.2",
|
"patch-package": "6.1.2",
|
||||||
"prettier": "1.12.0",
|
"prettier": "1.19.1",
|
||||||
"react-docgen-typescript": "1.2.6",
|
"react-docgen-typescript": "1.2.6",
|
||||||
"react-styleguidist": "7.0.1",
|
"react-styleguidist": "7.0.1",
|
||||||
"sass-loader": "7.2.0",
|
"sass-loader": "7.2.0",
|
||||||
|
|
|
@ -45,19 +45,13 @@ export const AppStage = (props: Props) => {
|
||||||
} = props;
|
} = props;
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const handleNext = React.useCallback(
|
const handleNext = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
history.push(next);
|
history.push(next);
|
||||||
},
|
}, [next]);
|
||||||
[next]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePrev = React.useCallback(
|
const handlePrev = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
history.push(prev);
|
history.push(prev);
|
||||||
},
|
}, [prev]);
|
||||||
[prev]
|
|
||||||
);
|
|
||||||
|
|
||||||
const addMoreCount = stickersDuck.useAddMoreCount();
|
const addMoreCount = stickersDuck.useAddMoreCount();
|
||||||
const toasts = stickersDuck.useToasts();
|
const toasts = stickersDuck.useToasts();
|
||||||
|
|
|
@ -37,26 +37,17 @@ export const MetaStage = () => {
|
||||||
accept: ['image/png', 'image/webp'],
|
accept: ['image/png', 'image/webp'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const onNext = React.useCallback(
|
const onNext = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setConfirming(true);
|
setConfirming(true);
|
||||||
},
|
}, [setConfirming]);
|
||||||
[setConfirming]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onCancel = React.useCallback(
|
const onCancel = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setConfirming(false);
|
setConfirming(false);
|
||||||
},
|
}, [setConfirming]);
|
||||||
[setConfirming]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onConfirm = React.useCallback(
|
const onConfirm = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
history.push('/upload');
|
history.push('/upload');
|
||||||
},
|
}, [setConfirming]);
|
||||||
[setConfirming]
|
|
||||||
);
|
|
||||||
|
|
||||||
const coverFrameClass = isDragActive
|
const coverFrameClass = isDragActive
|
||||||
? styles.coverFrameActive
|
? styles.coverFrameActive
|
||||||
|
|
|
@ -23,8 +23,7 @@ export const UploadStage = () => {
|
||||||
const total = orderedData.length;
|
const total = orderedData.length;
|
||||||
const [complete, setComplete] = React.useState(0);
|
const [complete, setComplete] = React.useState(0);
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const onProgress = () => setComplete(i => i + 1);
|
const onProgress = () => setComplete(i => i + 1);
|
||||||
try {
|
try {
|
||||||
|
@ -37,17 +36,13 @@ export const UploadStage = () => {
|
||||||
actions.setPackMeta(packMeta);
|
actions.setPackMeta(packMeta);
|
||||||
history.push('/share');
|
history.push('/share');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
actions.addToast('StickerCreator--Toasts--errorUploading', [
|
actions.addToast('StickerCreator--Toasts--errorUploading', [e.message]);
|
||||||
e.message,
|
|
||||||
]);
|
|
||||||
history.push('/add-meta');
|
history.push('/add-meta');
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [title, author, cover, orderedData]);
|
||||||
[title, author, cover, orderedData]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppStage empty={true}>
|
<AppStage empty={true}>
|
||||||
|
|
|
@ -12,8 +12,7 @@ export const ConfirmModal = React.memo(
|
||||||
const [popperRoot, setPopperRoot] = React.useState<HTMLDivElement>();
|
const [popperRoot, setPopperRoot] = React.useState<HTMLDivElement>();
|
||||||
|
|
||||||
// Create popper root and handle outside clicks
|
// Create popper root and handle outside clicks
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
setPopperRoot(root);
|
setPopperRoot(root);
|
||||||
document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
|
@ -28,9 +27,7 @@ export const ConfirmModal = React.memo(
|
||||||
document.body.removeChild(root);
|
document.body.removeChild(root);
|
||||||
document.removeEventListener('click', handleOutsideClick);
|
document.removeEventListener('click', handleOutsideClick);
|
||||||
};
|
};
|
||||||
},
|
}, [onCancel]);
|
||||||
[onCancel]
|
|
||||||
);
|
|
||||||
|
|
||||||
return popperRoot
|
return popperRoot
|
||||||
? createPortal(
|
? createPortal(
|
||||||
|
|
|
@ -9,8 +9,9 @@ export type Props = {
|
||||||
export const ShareButtons = React.memo(({ value }: Props) => {
|
export const ShareButtons = React.memo(({ value }: Props) => {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const buttonPaths = React.useMemo<Array<[string, string, string, string]>>(
|
const buttonPaths = React.useMemo<
|
||||||
() => {
|
Array<[string, string, string, string]>
|
||||||
|
>(() => {
|
||||||
const packUrl = encodeURIComponent(value);
|
const packUrl = encodeURIComponent(value);
|
||||||
const text = encodeURIComponent(
|
const text = encodeURIComponent(
|
||||||
`${i18n('StickerCreator--ShareStage--socialMessage')} ${value}`
|
`${i18n('StickerCreator--ShareStage--socialMessage')} ${value}`
|
||||||
|
@ -46,9 +47,7 @@ export const ShareButtons = React.memo(({ value }: Props) => {
|
||||||
`https://wa.me?text=${text}`,
|
`https://wa.me?text=${text}`,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
},
|
}, [i18n, value]);
|
||||||
[i18n, value]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|
|
@ -82,12 +82,9 @@ export const StickerFrame = React.memo(
|
||||||
] = React.useState<HTMLElement | null>(null);
|
] = React.useState<HTMLElement | null>(null);
|
||||||
const timerRef = React.useRef<number>();
|
const timerRef = React.useRef<number>();
|
||||||
|
|
||||||
const handleToggleEmojiPicker = React.useCallback(
|
const handleToggleEmojiPicker = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setEmojiPickerOpen(open => !open);
|
setEmojiPickerOpen(open => !open);
|
||||||
},
|
}, [setEmojiPickerOpen]);
|
||||||
[setEmojiPickerOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePickEmoji = React.useCallback(
|
const handlePickEmoji = React.useCallback(
|
||||||
(emoji: EmojiPickDataType) => {
|
(emoji: EmojiPickDataType) => {
|
||||||
|
@ -97,30 +94,21 @@ export const StickerFrame = React.memo(
|
||||||
[id, onPickEmoji, setEmojiPickerOpen]
|
[id, onPickEmoji, setEmojiPickerOpen]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleRemove = React.useCallback(
|
const handleRemove = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
onRemove(id);
|
onRemove(id);
|
||||||
},
|
}, [onRemove, id]);
|
||||||
[onRemove, id]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleMouseEnter = React.useCallback(
|
const handleMouseEnter = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
window.clearTimeout(timerRef.current);
|
window.clearTimeout(timerRef.current);
|
||||||
timerRef.current = window.setTimeout(() => {
|
timerRef.current = window.setTimeout(() => {
|
||||||
setPreviewActive(true);
|
setPreviewActive(true);
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
}, [timerRef, setPreviewActive]);
|
||||||
[timerRef, setPreviewActive]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleMouseLeave = React.useCallback(
|
const handleMouseLeave = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
clearTimeout(timerRef.current);
|
clearTimeout(timerRef.current);
|
||||||
setPreviewActive(false);
|
setPreviewActive(false);
|
||||||
},
|
}, [timerRef, setPreviewActive]);
|
||||||
[timerRef, setPreviewActive]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
|
@ -130,8 +118,7 @@ export const StickerFrame = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create popper root and handle outside clicks
|
// Create popper root and handle outside clicks
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (emojiPickerOpen) {
|
if (emojiPickerOpen) {
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
setEmojiPopperRoot(root);
|
setEmojiPopperRoot(root);
|
||||||
|
@ -150,12 +137,9 @@ export const StickerFrame = React.memo(
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [emojiPickerOpen, setEmojiPickerOpen, setEmojiPopperRoot]);
|
||||||
[emojiPickerOpen, setEmojiPickerOpen, setEmojiPopperRoot]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (mode !== 'pick-emoji' && image && previewActive) {
|
if (mode !== 'pick-emoji' && image && previewActive) {
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
setPreviewPopperRoot(root);
|
setPreviewPopperRoot(root);
|
||||||
|
@ -167,9 +151,7 @@ export const StickerFrame = React.memo(
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [mode, image, previewActive, setPreviewPopperRoot]);
|
||||||
[mode, image, previewActive, setPreviewPopperRoot]
|
|
||||||
);
|
|
||||||
|
|
||||||
const [dragActive, setDragActive] = React.useState<boolean>(false);
|
const [dragActive, setDragActive] = React.useState<boolean>(false);
|
||||||
const containerClass = dragActive ? styles.dragActive : styles.container;
|
const containerClass = dragActive ? styles.dragActive : styles.container;
|
||||||
|
|
|
@ -12,8 +12,7 @@ const DEFAULT_DISMISS = 1e4;
|
||||||
export const Toaster = React.memo(({ loaf, onDismiss, className }: Props) => {
|
export const Toaster = React.memo(({ loaf, onDismiss, className }: Props) => {
|
||||||
const slice = last(loaf);
|
const slice = last(loaf);
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (!slice) {
|
if (!slice) {
|
||||||
return noop;
|
return noop;
|
||||||
}
|
}
|
||||||
|
@ -25,9 +24,7 @@ export const Toaster = React.memo(({ loaf, onDismiss, className }: Props) => {
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
};
|
};
|
||||||
},
|
}, [slice, onDismiss]);
|
||||||
[slice, onDismiss]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!slice) {
|
if (!slice) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -12,15 +12,12 @@ export type Props = {
|
||||||
|
|
||||||
export const CopyText = React.memo(({ label, onCopy, value }: Props) => {
|
export const CopyText = React.memo(({ label, onCopy, value }: Props) => {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const handleClick = React.useCallback(
|
const handleClick = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
copy(value);
|
copy(value);
|
||||||
if (onCopy) {
|
if (onCopy) {
|
||||||
onCopy();
|
onCopy();
|
||||||
}
|
}
|
||||||
},
|
}, [onCopy, value]);
|
||||||
[onCopy, value]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|
|
@ -37,14 +37,11 @@ export const DropZone = (props: Props) => {
|
||||||
accept: ['image/png', 'image/webp'],
|
accept: ['image/png', 'image/webp'],
|
||||||
});
|
});
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (onDragActive) {
|
if (onDragActive) {
|
||||||
onDragActive(isDragActive);
|
onDragActive(isDragActive);
|
||||||
}
|
}
|
||||||
},
|
}, [isDragActive, onDragActive]);
|
||||||
[isDragActive, onDragActive]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...getRootProps({ className: getClassName(props, isDragActive) })}>
|
<div {...getRootProps({ className: getClassName(props, isDragActive) })}>
|
||||||
|
|
|
@ -16,12 +16,9 @@ const checkSvg = (
|
||||||
|
|
||||||
export const LabeledCheckbox = React.memo(
|
export const LabeledCheckbox = React.memo(
|
||||||
({ children, value, onChange }: Props) => {
|
({ children, value, onChange }: Props) => {
|
||||||
const handleChange = React.useCallback(
|
const handleChange = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
onChange(!value);
|
onChange(!value);
|
||||||
},
|
}, [onChange, value]);
|
||||||
[onChange, value]
|
|
||||||
);
|
|
||||||
|
|
||||||
const className = value ? styles.checkboxChecked : styles.checkbox;
|
const className = value ? styles.checkboxChecked : styles.checkbox;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const ProgressBar = React.memo(({ className, count, total }: Props) => (
|
||||||
<div className={classnames(styles.base, className)}>
|
<div className={classnames(styles.base, className)}>
|
||||||
<div
|
<div
|
||||||
className={styles.bar}
|
className={styles.bar}
|
||||||
style={{ width: `${Math.floor(count / total * 100)}%` }}
|
style={{ width: `${Math.floor((count / total) * 100)}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
|
|
|
@ -136,7 +136,7 @@ $conversation-colors: (
|
||||||
'teal': $color-conversation-teal,
|
'teal': $color-conversation-teal,
|
||||||
'green': $color-conversation-green,
|
'green': $color-conversation-green,
|
||||||
'light_green': $color-conversation-light_green,
|
'light_green': $color-conversation-light_green,
|
||||||
'blue_grey': $color-conversation-blue_grey
|
'blue_grey': $color-conversation-blue_grey,
|
||||||
);
|
);
|
||||||
$conversation-colors-tint: (
|
$conversation-colors-tint: (
|
||||||
'red': $color-conversation-red-tint,
|
'red': $color-conversation-red-tint,
|
||||||
|
@ -149,7 +149,7 @@ $conversation-colors-tint: (
|
||||||
'teal': $color-conversation-teal-tint,
|
'teal': $color-conversation-teal-tint,
|
||||||
'green': $color-conversation-green-tint,
|
'green': $color-conversation-green-tint,
|
||||||
'light_green': $color-conversation-light_green-tint,
|
'light_green': $color-conversation-light_green-tint,
|
||||||
'blue_grey': $color-conversation-blue_grey-tint
|
'blue_grey': $color-conversation-blue_grey-tint,
|
||||||
);
|
);
|
||||||
$conversation-colors-shade: (
|
$conversation-colors-shade: (
|
||||||
'red': $color-conversation-red-shade,
|
'red': $color-conversation-red-shade,
|
||||||
|
@ -162,7 +162,7 @@ $conversation-colors-shade: (
|
||||||
'teal': $color-conversation-teal-shade,
|
'teal': $color-conversation-teal-shade,
|
||||||
'green': $color-conversation-green-shade,
|
'green': $color-conversation-green-shade,
|
||||||
'light_green': $color-conversation-light_green-shade,
|
'light_green': $color-conversation-light_green-shade,
|
||||||
'blue_grey': $color-conversation-blue_grey-shade
|
'blue_grey': $color-conversation-blue_grey-shade,
|
||||||
);
|
);
|
||||||
|
|
||||||
// -- Non-V3 colors
|
// -- Non-V3 colors
|
||||||
|
|
|
@ -111,15 +111,12 @@ export const CompositionArea = ({
|
||||||
const editorRef = React.useRef<Editor>(null);
|
const editorRef = React.useRef<Editor>(null);
|
||||||
const inputApiRef = React.useRef<InputApi | undefined>();
|
const inputApiRef = React.useRef<InputApi | undefined>();
|
||||||
|
|
||||||
const handleForceSend = React.useCallback(
|
const handleForceSend = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setLarge(false);
|
setLarge(false);
|
||||||
if (inputApiRef.current) {
|
if (inputApiRef.current) {
|
||||||
inputApiRef.current.submit();
|
inputApiRef.current.submit();
|
||||||
}
|
}
|
||||||
},
|
}, [inputApiRef, setLarge]);
|
||||||
[inputApiRef, setLarge]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSubmit = React.useCallback<typeof onSubmit>(
|
const handleSubmit = React.useCallback<typeof onSubmit>(
|
||||||
(...args) => {
|
(...args) => {
|
||||||
|
@ -129,14 +126,11 @@ export const CompositionArea = ({
|
||||||
[setLarge, onSubmit]
|
[setLarge, onSubmit]
|
||||||
);
|
);
|
||||||
|
|
||||||
const focusInput = React.useCallback(
|
const focusInput = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
editorRef.current.focus();
|
editorRef.current.focus();
|
||||||
}
|
}
|
||||||
},
|
}, [editorRef]);
|
||||||
[editorRef]
|
|
||||||
);
|
|
||||||
|
|
||||||
const withStickers =
|
const withStickers =
|
||||||
countStickers({
|
countStickers({
|
||||||
|
@ -180,18 +174,14 @@ export const CompositionArea = ({
|
||||||
[inputApiRef, onPickEmoji]
|
[inputApiRef, onPickEmoji]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleToggleLarge = React.useCallback(
|
const handleToggleLarge = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setLarge(l => !l);
|
setLarge(l => !l);
|
||||||
},
|
}, [setLarge]);
|
||||||
[setLarge]
|
|
||||||
);
|
|
||||||
|
|
||||||
// The following is a work-around to allow react to lay-out backbone-managed
|
// The following is a work-around to allow react to lay-out backbone-managed
|
||||||
// dom nodes until those functions are in React
|
// dom nodes until those functions are in React
|
||||||
const micCellRef = React.useRef<HTMLDivElement>(null);
|
const micCellRef = React.useRef<HTMLDivElement>(null);
|
||||||
React.useLayoutEffect(
|
React.useLayoutEffect(() => {
|
||||||
() => {
|
|
||||||
const { current: micCellContainer } = micCellRef;
|
const { current: micCellContainer } = micCellRef;
|
||||||
if (micCellContainer && micCellEl) {
|
if (micCellContainer && micCellEl) {
|
||||||
emptyElement(micCellContainer);
|
emptyElement(micCellContainer);
|
||||||
|
@ -199,21 +189,16 @@ export const CompositionArea = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [micCellRef, micCellEl, large, dirty, showMic]);
|
||||||
[micCellRef, micCellEl, large, dirty, showMic]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useLayoutEffect(
|
React.useLayoutEffect(() => {
|
||||||
() => {
|
|
||||||
const { current: attSlot } = attSlotRef;
|
const { current: attSlot } = attSlotRef;
|
||||||
if (attSlot && attachmentListEl) {
|
if (attSlot && attachmentListEl) {
|
||||||
attSlot.appendChild(attachmentListEl);
|
attSlot.appendChild(attachmentListEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [attSlotRef, attachmentListEl]);
|
||||||
[attSlotRef, attachmentListEl]
|
|
||||||
);
|
|
||||||
|
|
||||||
const emojiButtonFragment = (
|
const emojiButtonFragment = (
|
||||||
<div className="module-composition-area__button-cell">
|
<div className="module-composition-area__button-cell">
|
||||||
|
@ -287,8 +272,7 @@ export const CompositionArea = ({
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
// Listen for cmd/ctrl-shift-x to toggle large composition mode
|
// Listen for cmd/ctrl-shift-x to toggle large composition mode
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handler = (e: KeyboardEvent) => {
|
const handler = (e: KeyboardEvent) => {
|
||||||
const { key, shiftKey, ctrlKey, metaKey } = e;
|
const { key, shiftKey, ctrlKey, metaKey } = e;
|
||||||
// When using the ctrl key, `key` is `'X'`. When using the cmd key, `key` is `'x'`
|
// When using the ctrl key, `key` is `'X'`. When using the cmd key, `key` is `'x'`
|
||||||
|
@ -309,9 +293,7 @@ export const CompositionArea = ({
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
},
|
}, [setLarge]);
|
||||||
[setLarge]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-composition-area">
|
<div className="module-composition-area">
|
||||||
|
|
|
@ -307,14 +307,11 @@ export const CompositionInput = ({
|
||||||
[onDirtyChange, onEditorStateChange, editorStateRef]
|
[onDirtyChange, onEditorStateChange, editorStateRef]
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetEmojiResults = React.useCallback(
|
const resetEmojiResults = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setEmojiResults([]);
|
setEmojiResults([]);
|
||||||
setEmojiResultsIndex(0);
|
setEmojiResultsIndex(0);
|
||||||
setSearchText('');
|
setSearchText('');
|
||||||
},
|
}, [setEmojiResults, setEmojiResultsIndex, setSearchText]);
|
||||||
[setEmojiResults, setEmojiResultsIndex, setSearchText]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleEditorStateChange = React.useCallback(
|
const handleEditorStateChange = React.useCallback(
|
||||||
(newState: EditorState) => {
|
(newState: EditorState) => {
|
||||||
|
@ -361,8 +358,7 @@ export const CompositionInput = ({
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleBeforeInput = React.useCallback(
|
const handleBeforeInput = React.useCallback((): DraftHandleValue => {
|
||||||
(): DraftHandleValue => {
|
|
||||||
if (!editorStateRef.current) {
|
if (!editorStateRef.current) {
|
||||||
return 'not-handled';
|
return 'not-handled';
|
||||||
}
|
}
|
||||||
|
@ -378,9 +374,7 @@ export const CompositionInput = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'not-handled';
|
return 'not-handled';
|
||||||
},
|
}, [onTextTooLong, editorStateRef]);
|
||||||
[onTextTooLong, editorStateRef]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePastedText = React.useCallback(
|
const handlePastedText = React.useCallback(
|
||||||
(pastedText: string): DraftHandleValue => {
|
(pastedText: string): DraftHandleValue => {
|
||||||
|
@ -406,25 +400,19 @@ export const CompositionInput = ({
|
||||||
[onTextTooLong, editorStateRef]
|
[onTextTooLong, editorStateRef]
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetEditorState = React.useCallback(
|
const resetEditorState = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
const newEmptyState = EditorState.createEmpty(compositeDecorator);
|
const newEmptyState = EditorState.createEmpty(compositeDecorator);
|
||||||
setAndTrackEditorState(newEmptyState);
|
setAndTrackEditorState(newEmptyState);
|
||||||
resetEmojiResults();
|
resetEmojiResults();
|
||||||
},
|
}, [editorStateRef, resetEmojiResults, setAndTrackEditorState]);
|
||||||
[editorStateRef, resetEmojiResults, setAndTrackEditorState]
|
|
||||||
);
|
|
||||||
|
|
||||||
const submit = React.useCallback(
|
const submit = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
const { current: state } = editorStateRef;
|
const { current: state } = editorStateRef;
|
||||||
const text = state.getCurrentContent().getPlainText();
|
const text = state.getCurrentContent().getPlainText();
|
||||||
const emojidText = replaceColons(text);
|
const emojidText = replaceColons(text);
|
||||||
const trimmedText = emojidText.trim();
|
const trimmedText = emojidText.trim();
|
||||||
onSubmit(trimmedText);
|
onSubmit(trimmedText);
|
||||||
},
|
}, [editorStateRef, onSubmit]);
|
||||||
[editorStateRef, onSubmit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleEditorSizeChange = React.useCallback(
|
const handleEditorSizeChange = React.useCallback(
|
||||||
(rect: ContentRect) => {
|
(rect: ContentRect) => {
|
||||||
|
@ -716,8 +704,7 @@ export const CompositionInput = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create popper root
|
// Create popper root
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (emojiResults.length > 0) {
|
if (emojiResults.length > 0) {
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
setPopperRoot(root);
|
setPopperRoot(root);
|
||||||
|
@ -730,31 +717,22 @@ export const CompositionInput = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [setPopperRoot, emojiResults]);
|
||||||
[setPopperRoot, emojiResults]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onFocus = React.useCallback(
|
const onFocus = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
focusRef.current = true;
|
focusRef.current = true;
|
||||||
},
|
}, [focusRef]);
|
||||||
[focusRef]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onBlur = React.useCallback(
|
const onBlur = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
focusRef.current = false;
|
focusRef.current = false;
|
||||||
},
|
}, [focusRef]);
|
||||||
[focusRef]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Manage focus
|
// Manage focus
|
||||||
// Chromium places the editor caret at the beginning of contenteditable divs on focus
|
// Chromium places the editor caret at the beginning of contenteditable divs on focus
|
||||||
// Here, we force the last known selection on focusin (doing this with onFocus wasn't behaving properly)
|
// Here, we force the last known selection on focusin (doing this with onFocus wasn't behaving properly)
|
||||||
// This needs to be done in an effect because React doesn't support focus{In,Out}
|
// This needs to be done in an effect because React doesn't support focus{In,Out}
|
||||||
// https://github.com/facebook/react/issues/6410
|
// https://github.com/facebook/react/issues/6410
|
||||||
React.useLayoutEffect(
|
React.useLayoutEffect(() => {
|
||||||
() => {
|
|
||||||
const { current: rootEl } = rootElRef;
|
const { current: rootEl } = rootElRef;
|
||||||
|
|
||||||
if (rootEl) {
|
if (rootEl) {
|
||||||
|
@ -774,9 +752,7 @@ export const CompositionInput = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [editorStateRef, rootElRef, setAndTrackEditorState]);
|
||||||
[editorStateRef, rootElRef, setAndTrackEditorState]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (inputApi) {
|
if (inputApi) {
|
||||||
inputApi.current = {
|
inputApi.current = {
|
||||||
|
@ -843,9 +819,7 @@ export const CompositionInput = ({
|
||||||
}}
|
}}
|
||||||
role="listbox"
|
role="listbox"
|
||||||
aria-expanded={true}
|
aria-expanded={true}
|
||||||
aria-activedescendant={`emoji-result--${
|
aria-activedescendant={`emoji-result--${emojiResults[emojiResultsIndex].short_name}`}
|
||||||
emojiResults[emojiResultsIndex].short_name
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{emojiResults.map((emoji, index) => (
|
{emojiResults.map((emoji, index) => (
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -30,8 +30,7 @@ export const ConfirmationDialog = React.memo(
|
||||||
affirmativeText,
|
affirmativeText,
|
||||||
negativeText,
|
negativeText,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handler = ({ key }: KeyboardEvent) => {
|
const handler = ({ key }: KeyboardEvent) => {
|
||||||
if (key === 'Escape') {
|
if (key === 'Escape') {
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -42,9 +41,7 @@ export const ConfirmationDialog = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
},
|
}, [onClose]);
|
||||||
[onClose]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleCancel = React.useCallback(
|
const handleCancel = React.useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
|
@ -55,25 +52,19 @@ export const ConfirmationDialog = React.memo(
|
||||||
[onClose]
|
[onClose]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleNegative = React.useCallback(
|
const handleNegative = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
onClose();
|
onClose();
|
||||||
if (onNegative) {
|
if (onNegative) {
|
||||||
onNegative();
|
onNegative();
|
||||||
}
|
}
|
||||||
},
|
}, [onClose, onNegative]);
|
||||||
[onClose, onNegative]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAffirmative = React.useCallback(
|
const handleAffirmative = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
onClose();
|
onClose();
|
||||||
if (onAffirmative) {
|
if (onAffirmative) {
|
||||||
onAffirmative();
|
onAffirmative();
|
||||||
}
|
}
|
||||||
},
|
}, [onClose, onAffirmative]);
|
||||||
[onClose, onAffirmative]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-confirmation-dialog__container">
|
<div className="module-confirmation-dialog__container">
|
||||||
|
|
|
@ -39,8 +39,7 @@ export const ConfirmationModal = React.memo(
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handler = (event: KeyboardEvent) => {
|
const handler = (event: KeyboardEvent) => {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -54,9 +53,7 @@ export const ConfirmationModal = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
},
|
}, [onClose]);
|
||||||
[onClose]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleCancel = React.useCallback(
|
const handleCancel = React.useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
|
|
|
@ -195,9 +195,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'module-conversation-list-item__message__status-icon',
|
'module-conversation-list-item__message__status-icon',
|
||||||
`module-conversation-list-item__message__status-icon--${
|
`module-conversation-list-item__message__status-icon--${lastMessage.status}`
|
||||||
lastMessage.status
|
|
||||||
}`
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -23,9 +23,11 @@ interface Props {
|
||||||
close: () => void;
|
close: () => void;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
media: Array<MediaItemType>;
|
media: Array<MediaItemType>;
|
||||||
onSave?: (
|
onSave?: (options: {
|
||||||
options: { attachment: AttachmentType; message: Message; index: number }
|
attachment: AttachmentType;
|
||||||
) => void;
|
message: Message;
|
||||||
|
index: number;
|
||||||
|
}) => void;
|
||||||
selectedIndex: number;
|
selectedIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,29 +110,24 @@ export type PropsActions = {
|
||||||
showMessageDetail: (id: string) => void;
|
showMessageDetail: (id: string) => void;
|
||||||
|
|
||||||
openConversation: (conversationId: string, messageId?: string) => void;
|
openConversation: (conversationId: string, messageId?: string) => void;
|
||||||
showContactDetail: (
|
showContactDetail: (options: {
|
||||||
options: { contact: ContactType; signalAccount?: string }
|
contact: ContactType;
|
||||||
) => void;
|
signalAccount?: string;
|
||||||
|
}) => void;
|
||||||
|
|
||||||
showVisualAttachment: (
|
showVisualAttachment: (options: {
|
||||||
options: { attachment: AttachmentType; messageId: string }
|
attachment: AttachmentType;
|
||||||
) => void;
|
messageId: string;
|
||||||
downloadAttachment: (
|
}) => void;
|
||||||
options: {
|
downloadAttachment: (options: {
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
isDangerous: boolean;
|
isDangerous: boolean;
|
||||||
}
|
}) => void;
|
||||||
) => void;
|
|
||||||
displayTapToViewMessage: (messageId: string) => unknown;
|
displayTapToViewMessage: (messageId: string) => unknown;
|
||||||
|
|
||||||
openLink: (url: string) => void;
|
openLink: (url: string) => void;
|
||||||
scrollToQuotedMessage: (
|
scrollToQuotedMessage: (options: { author: string; sentAt: number }) => void;
|
||||||
options: {
|
|
||||||
author: string;
|
|
||||||
sentAt: number;
|
|
||||||
}
|
|
||||||
) => void;
|
|
||||||
selectMessage?: (messageId: string, conversationId: string) => unknown;
|
selectMessage?: (messageId: string, conversationId: string) => unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,27 +37,20 @@ export const EmojiButton = React.memo(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClickButton = React.useCallback(
|
const handleClickButton = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
if (popperRoot) {
|
if (popperRoot) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
} else {
|
} else {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}
|
}
|
||||||
},
|
}, [popperRoot, setOpen]);
|
||||||
[popperRoot, setOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClose = React.useCallback(
|
const handleClose = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
},
|
}, [setOpen]);
|
||||||
[setOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create popper root and handle outside clicks
|
// Create popper root and handle outside clicks
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (open) {
|
if (open) {
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
setPopperRoot(root);
|
setPopperRoot(root);
|
||||||
|
@ -77,13 +70,10 @@ export const EmojiButton = React.memo(
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [open, setOpen, setPopperRoot]);
|
||||||
[open, setOpen, setPopperRoot]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Install keyboard shortcut to open emoji picker
|
// Install keyboard shortcut to open emoji picker
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handleKeydown = (event: KeyboardEvent) => {
|
const handleKeydown = (event: KeyboardEvent) => {
|
||||||
const { ctrlKey, key, metaKey, shiftKey } = event;
|
const { ctrlKey, key, metaKey, shiftKey } = event;
|
||||||
const commandKey = get(window, 'platform') === 'darwin' && metaKey;
|
const commandKey = get(window, 'platform') === 'darwin' && metaKey;
|
||||||
|
@ -108,9 +98,7 @@ export const EmojiButton = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handleKeydown);
|
document.removeEventListener('keydown', handleKeydown);
|
||||||
};
|
};
|
||||||
},
|
}, [open, setOpen]);
|
||||||
[open, setOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Manager>
|
<Manager>
|
||||||
|
|
|
@ -82,14 +82,11 @@ export const EmojiPicker = React.memo(
|
||||||
const [scrollToRow, setScrollToRow] = React.useState(0);
|
const [scrollToRow, setScrollToRow] = React.useState(0);
|
||||||
const [selectedTone, setSelectedTone] = React.useState(skinTone);
|
const [selectedTone, setSelectedTone] = React.useState(skinTone);
|
||||||
|
|
||||||
const handleToggleSearch = React.useCallback(
|
const handleToggleSearch = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setSearchText('');
|
setSearchText('');
|
||||||
setSelectedCategory(categories[0]);
|
setSelectedCategory(categories[0]);
|
||||||
setSearchMode(m => !m);
|
setSearchMode(m => !m);
|
||||||
},
|
}, [setSearchText, setSearchMode]);
|
||||||
[setSearchText, setSearchMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const debounceSearchChange = React.useMemo(
|
const debounceSearchChange = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
@ -141,8 +138,7 @@ export const EmojiPicker = React.memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle escape key
|
// Handle escape key
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handler = (event: KeyboardEvent) => {
|
const handler = (event: KeyboardEvent) => {
|
||||||
if (searchMode && event.key === 'Escape') {
|
if (searchMode && event.key === 'Escape') {
|
||||||
setSearchText('');
|
setSearchText('');
|
||||||
|
@ -175,9 +171,7 @@ export const EmojiPicker = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
},
|
}, [onClose, searchMode]);
|
||||||
[onClose, searchMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Restore focus on teardown
|
// Restore focus on teardown
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -193,25 +187,27 @@ export const EmojiPicker = React.memo(
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const emojiGrid = React.useMemo(
|
const emojiGrid = React.useMemo(() => {
|
||||||
() => {
|
|
||||||
if (searchText) {
|
if (searchText) {
|
||||||
return chunk(search(searchText).map(e => e.short_name), COL_COUNT);
|
return chunk(
|
||||||
|
search(searchText).map(e => e.short_name),
|
||||||
|
COL_COUNT
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, ...cats] = categories;
|
const [, ...cats] = categories;
|
||||||
|
|
||||||
const chunks = flatMap(cats, cat =>
|
const chunks = flatMap(cats, cat =>
|
||||||
chunk(dataByCategory[cat].map(e => e.short_name), COL_COUNT)
|
chunk(
|
||||||
|
dataByCategory[cat].map(e => e.short_name),
|
||||||
|
COL_COUNT
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return [...chunk(firstRecent, COL_COUNT), ...chunks];
|
return [...chunk(firstRecent, COL_COUNT), ...chunks];
|
||||||
},
|
}, [dataByCategory, categories, firstRecent, searchText]);
|
||||||
[dataByCategory, categories, firstRecent, searchText]
|
|
||||||
);
|
|
||||||
|
|
||||||
const catRowEnds = React.useMemo(
|
const catRowEnds = React.useMemo(() => {
|
||||||
() => {
|
|
||||||
const rowEnds: Array<number> = [
|
const rowEnds: Array<number> = [
|
||||||
Math.ceil(firstRecent.length / COL_COUNT) - 1,
|
Math.ceil(firstRecent.length / COL_COUNT) - 1,
|
||||||
];
|
];
|
||||||
|
@ -225,18 +221,13 @@ export const EmojiPicker = React.memo(
|
||||||
});
|
});
|
||||||
|
|
||||||
return rowEnds;
|
return rowEnds;
|
||||||
},
|
}, [categories, dataByCategory]);
|
||||||
[categories, dataByCategory]
|
|
||||||
);
|
|
||||||
|
|
||||||
const catToRowOffsets = React.useMemo(
|
const catToRowOffsets = React.useMemo(() => {
|
||||||
() => {
|
|
||||||
const offsets = initial(catRowEnds).map(i => i + 1);
|
const offsets = initial(catRowEnds).map(i => i + 1);
|
||||||
|
|
||||||
return zipObject(categories, [0, ...offsets]);
|
return zipObject(categories, [0, ...offsets]);
|
||||||
},
|
}, [categories, catRowEnds]);
|
||||||
[categories, catRowEnds]
|
|
||||||
);
|
|
||||||
|
|
||||||
const catOffsetEntries = React.useMemo(
|
const catOffsetEntries = React.useMemo(
|
||||||
() => Object.entries(catToRowOffsets),
|
() => Object.entries(catToRowOffsets),
|
||||||
|
@ -331,8 +322,7 @@ export const EmojiPicker = React.memo(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
categories.map(
|
categories.map(cat =>
|
||||||
cat =>
|
|
||||||
cat === 'recents' && firstRecent.length === 0 ? null : (
|
cat === 'recents' && firstRecent.length === 0 ? null : (
|
||||||
<button
|
<button
|
||||||
key={cat}
|
key={cat}
|
||||||
|
|
|
@ -52,8 +52,7 @@ export const StickerButton = React.memo(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClickButton = React.useCallback(
|
const handleClickButton = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
// Clear tooltip state
|
// Clear tooltip state
|
||||||
clearInstalledStickerPack();
|
clearInstalledStickerPack();
|
||||||
clearShowIntroduction();
|
clearShowIntroduction();
|
||||||
|
@ -66,15 +65,13 @@ export const StickerButton = React.memo(
|
||||||
} else {
|
} else {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}
|
}
|
||||||
},
|
}, [
|
||||||
[
|
|
||||||
clearInstalledStickerPack,
|
clearInstalledStickerPack,
|
||||||
onClickAddPack,
|
onClickAddPack,
|
||||||
installedPacks,
|
installedPacks,
|
||||||
popperRoot,
|
popperRoot,
|
||||||
setOpen,
|
setOpen,
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
const handlePickSticker = React.useCallback(
|
const handlePickSticker = React.useCallback(
|
||||||
(packId: string, stickerId: number) => {
|
(packId: string, stickerId: number) => {
|
||||||
|
@ -84,44 +81,32 @@ export const StickerButton = React.memo(
|
||||||
[setOpen, onPickSticker]
|
[setOpen, onPickSticker]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClose = React.useCallback(
|
const handleClose = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
},
|
}, [setOpen]);
|
||||||
[setOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClickAddPack = React.useCallback(
|
const handleClickAddPack = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
if (showPickerHint) {
|
if (showPickerHint) {
|
||||||
clearShowPickerHint();
|
clearShowPickerHint();
|
||||||
}
|
}
|
||||||
onClickAddPack();
|
onClickAddPack();
|
||||||
},
|
}, [onClickAddPack, showPickerHint, clearShowPickerHint]);
|
||||||
[onClickAddPack, showPickerHint, clearShowPickerHint]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClearIntroduction = React.useCallback(
|
const handleClearIntroduction = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
clearInstalledStickerPack();
|
clearInstalledStickerPack();
|
||||||
clearShowIntroduction();
|
clearShowIntroduction();
|
||||||
},
|
}, [clearInstalledStickerPack, clearShowIntroduction]);
|
||||||
[clearInstalledStickerPack, clearShowIntroduction]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create popper root and handle outside clicks
|
// Create popper root and handle outside clicks
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (open) {
|
if (open) {
|
||||||
const root = document.createElement('div');
|
const root = document.createElement('div');
|
||||||
setPopperRoot(root);
|
setPopperRoot(root);
|
||||||
document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
const handleOutsideClick = ({ target }: MouseEvent) => {
|
const handleOutsideClick = ({ target }: MouseEvent) => {
|
||||||
const targetElement = target as HTMLElement;
|
const targetElement = target as HTMLElement;
|
||||||
const className = targetElement
|
const className = targetElement ? targetElement.className || '' : '';
|
||||||
? targetElement.className || ''
|
|
||||||
: '';
|
|
||||||
|
|
||||||
// We need to special-case sticker picker header buttons, because they can
|
// We need to special-case sticker picker header buttons, because they can
|
||||||
// disappear after being clicked, which breaks the .contains() check below.
|
// disappear after being clicked, which breaks the .contains() check below.
|
||||||
|
@ -143,13 +128,10 @@ export const StickerButton = React.memo(
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [open, setOpen, setPopperRoot]);
|
||||||
[open, setOpen, setPopperRoot]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Install keyboard shortcut to open sticker picker
|
// Install keyboard shortcut to open sticker picker
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handleKeydown = (event: KeyboardEvent) => {
|
const handleKeydown = (event: KeyboardEvent) => {
|
||||||
const { ctrlKey, key, metaKey, shiftKey } = event;
|
const { ctrlKey, key, metaKey, shiftKey } = event;
|
||||||
const commandKey = get(window, 'platform') === 'darwin' && metaKey;
|
const commandKey = get(window, 'platform') === 'darwin' && metaKey;
|
||||||
|
@ -174,13 +156,10 @@ export const StickerButton = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handleKeydown);
|
document.removeEventListener('keydown', handleKeydown);
|
||||||
};
|
};
|
||||||
},
|
}, [open, setOpen]);
|
||||||
[open, setOpen]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clear the installed pack after one minute
|
// Clear the installed pack after one minute
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (installedPack) {
|
if (installedPack) {
|
||||||
// tslint:disable-next-line:no-string-based-set-timeout
|
// tslint:disable-next-line:no-string-based-set-timeout
|
||||||
const timerId = setTimeout(clearInstalledStickerPack, 10 * 1000);
|
const timerId = setTimeout(clearInstalledStickerPack, 10 * 1000);
|
||||||
|
@ -191,9 +170,7 @@ export const StickerButton = React.memo(
|
||||||
}
|
}
|
||||||
|
|
||||||
return noop;
|
return noop;
|
||||||
},
|
}, [installedPack, clearInstalledStickerPack]);
|
||||||
[installedPack, clearInstalledStickerPack]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
countStickers({
|
countStickers({
|
||||||
|
|
|
@ -53,12 +53,9 @@ export const StickerManager = React.memo(
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const clearPackToPreview = React.useCallback(
|
const clearPackToPreview = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setPackToPreview(null);
|
setPackToPreview(null);
|
||||||
},
|
}, [setPackToPreview]);
|
||||||
[setPackToPreview]
|
|
||||||
);
|
|
||||||
|
|
||||||
const previewPack = React.useCallback(
|
const previewPack = React.useCallback(
|
||||||
(pack: StickerPackType) => {
|
(pack: StickerPackType) => {
|
||||||
|
|
|
@ -26,12 +26,9 @@ export const StickerManagerPackRow = React.memo(
|
||||||
const { id, key, isBlessed } = pack;
|
const { id, key, isBlessed } = pack;
|
||||||
const [uninstalling, setUninstalling] = React.useState(false);
|
const [uninstalling, setUninstalling] = React.useState(false);
|
||||||
|
|
||||||
const clearUninstalling = React.useCallback(
|
const clearUninstalling = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setUninstalling(false);
|
setUninstalling(false);
|
||||||
},
|
}, [setUninstalling]);
|
||||||
[setUninstalling]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleInstall = React.useCallback(
|
const handleInstall = React.useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
|
@ -55,15 +52,12 @@ export const StickerManagerPackRow = React.memo(
|
||||||
[setUninstalling, id, key, isBlessed]
|
[setUninstalling, id, key, isBlessed]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleConfirmUninstall = React.useCallback(
|
const handleConfirmUninstall = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
clearUninstalling();
|
clearUninstalling();
|
||||||
if (uninstallStickerPack) {
|
if (uninstallStickerPack) {
|
||||||
uninstallStickerPack(id, key);
|
uninstallStickerPack(id, key);
|
||||||
}
|
}
|
||||||
},
|
}, [id, key, clearUninstalling]);
|
||||||
[id, key, clearUninstalling]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleKeyDown = React.useCallback(
|
const handleKeyDown = React.useCallback(
|
||||||
(event: React.KeyboardEvent) => {
|
(event: React.KeyboardEvent) => {
|
||||||
|
|
|
@ -42,7 +42,7 @@ function getPacksPageOffset(page: number, packs: number): number {
|
||||||
if (isLastPacksPage(page, packs)) {
|
if (isLastPacksPage(page, packs)) {
|
||||||
return (
|
return (
|
||||||
PACK_PAGE_WIDTH * (Math.floor(packs / PACKS_PAGE_SIZE) - 1) +
|
PACK_PAGE_WIDTH * (Math.floor(packs / PACKS_PAGE_SIZE) - 1) +
|
||||||
(packs % PACKS_PAGE_SIZE - 1) * PACK_ICON_WIDTH
|
((packs % PACKS_PAGE_SIZE) - 1) * PACK_ICON_WIDTH
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,27 +82,19 @@ export const StickerPicker = React.memo(
|
||||||
const {
|
const {
|
||||||
stickers = recentStickers,
|
stickers = recentStickers,
|
||||||
title: packTitle = 'Recent Stickers',
|
title: packTitle = 'Recent Stickers',
|
||||||
} =
|
} = selectedPack || {};
|
||||||
selectedPack || {};
|
|
||||||
|
|
||||||
const [isUsingKeyboard, setIsUsingKeyboard] = React.useState(false);
|
const [isUsingKeyboard, setIsUsingKeyboard] = React.useState(false);
|
||||||
const [packsPage, setPacksPage] = React.useState(0);
|
const [packsPage, setPacksPage] = React.useState(0);
|
||||||
const onClickPrevPackPage = React.useCallback(
|
const onClickPrevPackPage = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
setPacksPage(i => i - 1);
|
setPacksPage(i => i - 1);
|
||||||
},
|
}, [setPacksPage]);
|
||||||
[setPacksPage]
|
const onClickNextPackPage = React.useCallback(() => {
|
||||||
);
|
|
||||||
const onClickNextPackPage = React.useCallback(
|
|
||||||
() => {
|
|
||||||
setPacksPage(i => i + 1);
|
setPacksPage(i => i + 1);
|
||||||
},
|
}, [setPacksPage]);
|
||||||
[setPacksPage]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handle escape key
|
// Handle escape key
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handler = (event: KeyboardEvent) => {
|
const handler = (event: KeyboardEvent) => {
|
||||||
if (event.key === 'Tab') {
|
if (event.key === 'Tab') {
|
||||||
// We do NOT prevent default here to allow Tab to be used normally
|
// We do NOT prevent default here to allow Tab to be used normally
|
||||||
|
@ -127,9 +119,7 @@ export const StickerPicker = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
},
|
}, [onClose]);
|
||||||
[onClose]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Focus popup on after initial render, restore focus on teardown
|
// Focus popup on after initial render, restore focus on teardown
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
@ -79,8 +79,7 @@ export const StickerPreviewModal = React.memo(
|
||||||
const [confirmingUninstall, setConfirmingUninstall] = React.useState(false);
|
const [confirmingUninstall, setConfirmingUninstall] = React.useState(false);
|
||||||
|
|
||||||
// Restore focus on teardown
|
// Restore focus on teardown
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -95,9 +94,7 @@ export const StickerPreviewModal = React.memo(
|
||||||
lastFocused.focus();
|
lastFocused.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
}, [root]);
|
||||||
[root]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
|
@ -126,8 +123,7 @@ export const StickerPreviewModal = React.memo(
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isInstalled = Boolean(pack && pack.status === 'installed');
|
const isInstalled = Boolean(pack && pack.status === 'installed');
|
||||||
const handleToggleInstall = React.useCallback(
|
const handleToggleInstall = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
if (!pack) {
|
if (!pack) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -140,24 +136,24 @@ export const StickerPreviewModal = React.memo(
|
||||||
installStickerPack(pack.id, pack.key);
|
installStickerPack(pack.id, pack.key);
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
},
|
}, [
|
||||||
[isInstalled, pack, setConfirmingUninstall, installStickerPack, onClose]
|
isInstalled,
|
||||||
);
|
pack,
|
||||||
|
setConfirmingUninstall,
|
||||||
|
installStickerPack,
|
||||||
|
onClose,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleUninstall = React.useCallback(
|
const handleUninstall = React.useCallback(() => {
|
||||||
() => {
|
|
||||||
if (!pack) {
|
if (!pack) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uninstallStickerPack(pack.id, pack.key);
|
uninstallStickerPack(pack.id, pack.key);
|
||||||
setConfirmingUninstall(false);
|
setConfirmingUninstall(false);
|
||||||
// onClose is called by the confirmation modal
|
// onClose is called by the confirmation modal
|
||||||
},
|
}, [uninstallStickerPack, setConfirmingUninstall, pack]);
|
||||||
[uninstallStickerPack, setConfirmingUninstall, pack]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(() => {
|
||||||
() => {
|
|
||||||
const handler = ({ key }: KeyboardEvent) => {
|
const handler = ({ key }: KeyboardEvent) => {
|
||||||
if (key === 'Escape') {
|
if (key === 'Escape') {
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -169,9 +165,7 @@ export const StickerPreviewModal = React.memo(
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handler);
|
document.removeEventListener('keydown', handler);
|
||||||
};
|
};
|
||||||
},
|
}, [onClose]);
|
||||||
[onClose]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClickToClose = React.useCallback(
|
const handleClickToClose = React.useCallback(
|
||||||
(e: React.MouseEvent) => {
|
(e: React.MouseEvent) => {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
export type RenderTextCallbackType = (
|
export type RenderTextCallbackType = (options: {
|
||||||
options: {
|
|
||||||
text: string;
|
text: string;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}) => JSX.Element | string;
|
||||||
) => JSX.Element | string;
|
|
||||||
|
|
||||||
export type LocalizerType = (key: string, values?: Array<string>) => string;
|
export type LocalizerType = (key: string, values?: Array<string>) => string;
|
||||||
|
|
||||||
|
|
|
@ -9234,9 +9234,9 @@
|
||||||
"rule": "React-createRef",
|
"rule": "React-createRef",
|
||||||
"path": "ts/components/conversation/Message.tsx",
|
"path": "ts/components/conversation/Message.tsx",
|
||||||
"line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();",
|
"line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();",
|
||||||
"lineNumber": 155,
|
"lineNumber": 150,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2019-11-01T22:46:33.013Z",
|
"updated": "2020-01-06T17:05:33.013Z",
|
||||||
"reasonDetail": "Used for setting focus only"
|
"reasonDetail": "Used for setting focus only"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function getTimerBucket(expiration: number, length: number): string {
|
||||||
return '60';
|
return '60';
|
||||||
}
|
}
|
||||||
|
|
||||||
const bucket = Math.round(delta / length * 12);
|
const bucket = Math.round((delta / length) * 12);
|
||||||
|
|
||||||
return padStart(String(bucket * 5), 2, '0');
|
return padStart(String(bucket * 5), 2, '0');
|
||||||
}
|
}
|
||||||
|
|
|
@ -12527,9 +12527,10 @@ preserve@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||||
|
|
||||||
prettier@1.12.0:
|
prettier@1.19.1:
|
||||||
version "1.12.0"
|
version "1.19.1"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.0.tgz#d26fc5894b9230de97629b39cae225b503724ce8"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||||
|
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
||||||
|
|
||||||
pretty-bytes@^1.0.2:
|
pretty-bytes@^1.0.2:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
|
|
Loading…
Reference in a new issue