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!
|
||||
-->
|
||||
|
||||
* [ ] I have searched open and closed issues for duplicates
|
||||
- [ ] I have searched open and closed issues for duplicates
|
||||
<!--
|
||||
You can search all issues here:
|
||||
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:
|
||||
|
||||
* [ ] 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 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/)
|
||||
|
||||
### 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 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
|
||||
* [ ] 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 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 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))
|
||||
- [ ] My changes are ready to be shipped to users
|
||||
|
||||
### Description
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ Then you need `git`, if you don't have that yet: https://git-scm.com/
|
|||
### Windows
|
||||
|
||||
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
|
||||
* 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>)
|
||||
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:
|
||||
|
||||
* macOS: `~/Library/Application Support/Signal`
|
||||
* Linux: `~/.config/Signal`
|
||||
* Windows 10: `C:\Users\<YourName>\AppData\Roaming\Signal`
|
||||
- macOS: `~/Library/Application Support/Signal`
|
||||
- Linux: `~/.config/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
|
||||
`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.
|
||||
|
||||
* 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.
|
||||
* 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
|
||||
[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
|
||||
[`_locales/en/messages.json`](_locales/en/messages.json). Other locales are generated
|
||||
automatically based on that file and then periodically uploaded to Transifex for
|
||||
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.
|
||||
This ensures that your changes will merge cleanly when you open your PR.
|
||||
* Be sure to add and run tests!
|
||||
* Make sure the diff between our master and your branch contains only the
|
||||
- Be sure to add and run tests!
|
||||
- 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
|
||||
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.
|
||||
* 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
|
||||
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
|
||||
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/)
|
||||
for some tips on formatting. As far as content, try to include in your
|
||||
summary
|
||||
|
|
12
Gruntfile.js
12
Gruntfile.js
|
@ -150,18 +150,12 @@ module.exports = grunt => {
|
|||
},
|
||||
'test-release': {
|
||||
osx: {
|
||||
archive: `mac/${
|
||||
packageJson.productName
|
||||
}.app/Contents/Resources/app.asar`,
|
||||
exe: `mac/${packageJson.productName}.app/Contents/MacOS/${
|
||||
packageJson.productName
|
||||
}`,
|
||||
archive: `mac/${packageJson.productName}.app/Contents/Resources/app.asar`,
|
||||
exe: `mac/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`,
|
||||
},
|
||||
mas: {
|
||||
archive: 'mas/Signal.app/Contents/Resources/app.asar',
|
||||
exe: `mas/${packageJson.productName}.app/Contents/MacOS/${
|
||||
packageJson.productName
|
||||
}`,
|
||||
exe: `mas/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`,
|
||||
},
|
||||
linux: {
|
||||
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.
|
||||
|
||||
* _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.
|
||||
* _Linux:_ Follow the production instructions to set up the APT repository and run `apt install signal-desktop-beta`.
|
||||
- _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.
|
||||
- _Linux:_ Follow the production instructions to set up the APT repository and run `apt install signal-desktop-beta`.
|
||||
|
||||
## Got a question?
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -43,9 +43,7 @@ async function initialize() {
|
|||
try {
|
||||
await cleanupLogs(logPath);
|
||||
} catch (error) {
|
||||
const errorString = `Failed to clean logs; deleting all. Error: ${
|
||||
error.stack
|
||||
}`;
|
||||
const errorString = `Failed to clean logs; deleting all. Error: ${error.stack}`;
|
||||
console.error(errorString);
|
||||
await deleteAllLogs(logPath);
|
||||
mkdirp.sync(logPath);
|
||||
|
|
|
@ -3,13 +3,11 @@
|
|||
"cdnUrl": "https://cdn-staging.signal.org",
|
||||
"contentProxyUrl": "http://contentproxy.signal.org:443",
|
||||
"updatesUrl": "https://updates2.signal.org/desktop",
|
||||
"updatesPublicKey":
|
||||
"fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
||||
"updatesPublicKey": "fd7dd3de7149dc0a127909fee7de0f7620ddd0de061b37a2c303e37de802a401",
|
||||
"updatesEnabled": false,
|
||||
"openDevTools": false,
|
||||
"buildExpiration": 0,
|
||||
"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",
|
||||
"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",
|
||||
"import": false,
|
||||
"serverTrustRoot": "BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx"
|
||||
}
|
||||
|
|
|
@ -498,9 +498,7 @@
|
|||
idleDetector = new IdleDetector();
|
||||
let isMigrationWithIndexComplete = false;
|
||||
window.log.info(
|
||||
`Starting background data migration. Target version: ${
|
||||
Message.CURRENT_SCHEMA_VERSION
|
||||
}`
|
||||
`Starting background data migration. Target version: ${Message.CURRENT_SCHEMA_VERSION}`
|
||||
);
|
||||
idleDetector.on('idle', async () => {
|
||||
const NUM_MESSAGES_PER_BATCH = 1;
|
||||
|
@ -1611,7 +1609,9 @@
|
|||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||
ourNumber,
|
||||
{ syncMessage: true }
|
||||
{
|
||||
syncMessage: true,
|
||||
}
|
||||
);
|
||||
|
||||
const installedStickerPacks = window.Signal.Stickers.getInstalledStickerPacks();
|
||||
|
|
|
@ -955,7 +955,9 @@
|
|||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||
ourNumber,
|
||||
{ syncMessage: true }
|
||||
{
|
||||
syncMessage: true,
|
||||
}
|
||||
);
|
||||
|
||||
await wrap(
|
||||
|
@ -1480,7 +1482,9 @@
|
|||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||
ourNumber,
|
||||
{ syncMessage: true }
|
||||
{
|
||||
syncMessage: true,
|
||||
}
|
||||
);
|
||||
|
||||
this.syncPromise = this.syncPromise || Promise.resolve();
|
||||
|
|
|
@ -396,7 +396,7 @@ function getRandomValue(low, high) {
|
|||
|
||||
// Because high and low are inclusive
|
||||
const mod = diff + 1;
|
||||
return bytes[0] % mod + low;
|
||||
return (bytes[0] % mod) + low;
|
||||
}
|
||||
|
||||
function getZeroes(n) {
|
||||
|
@ -454,9 +454,7 @@ function splitBytes(buffer, ...lengths) {
|
|||
|
||||
if (total !== buffer.byteLength) {
|
||||
throw new Error(
|
||||
`Requested lengths total ${total} does not match source total ${
|
||||
buffer.byteLength
|
||||
}`
|
||||
`Requested lengths total ${total} does not match source total ${buffer.byteLength}`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ function _getString(thing) {
|
|||
return thing;
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
function _b64ToUint6(nChr) {
|
||||
return nChr > 64 && nChr < 91
|
||||
? nChr - 65
|
||||
|
|
|
@ -1098,9 +1098,7 @@
|
|||
const data = await readDraftData(attachment.path);
|
||||
if (data.byteLength !== attachment.size) {
|
||||
window.log.error(
|
||||
`Attachment size from disk ${
|
||||
data.byteLength
|
||||
} did not match attachment size ${attachment.size}`
|
||||
`Attachment size from disk ${data.byteLength} did not match attachment size ${attachment.size}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
@ -1411,7 +1409,7 @@
|
|||
blob = window.dataURLToBlobSync(
|
||||
canvas.toDataURL(targetContentType, quality)
|
||||
);
|
||||
quality = quality * maxSize / blob.size;
|
||||
quality = (quality * maxSize) / blob.size;
|
||||
// NOTE: During testing with a large image, we observed the
|
||||
// `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
|
||||
|
|
|
@ -1198,9 +1198,7 @@ MessageReceiver.prototype.extend({
|
|||
|
||||
if (!_.isNumber(size)) {
|
||||
throw new Error(
|
||||
`downloadAttachment: Size was not provided, actual size was ${
|
||||
data.byteLength
|
||||
}`
|
||||
`downloadAttachment: Size was not provided, actual size was ${data.byteLength}`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1251,11 +1249,7 @@ MessageReceiver.prototype.extend({
|
|||
|
||||
if (envelopeTimestamp !== decryptedTimestamp) {
|
||||
throw new Error(
|
||||
`Timestamp ${
|
||||
decrypted.timestamp
|
||||
} in DataMessage did not match envelope timestamp ${
|
||||
envelope.timestamp
|
||||
}`
|
||||
`Timestamp ${decrypted.timestamp} in DataMessage did not match envelope timestamp ${envelope.timestamp}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ OutgoingMessage.prototype = {
|
|||
}
|
||||
|
||||
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
|
||||
// 404 should throw UnregisteredUserError
|
||||
// all other network errors can be retried later.
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
}
|
||||
const protos = result.build('signalservice');
|
||||
if (!protos) {
|
||||
const text = `Error loading protos from ${filename} (root: ${
|
||||
window.PROTO_ROOT
|
||||
})`;
|
||||
const text = `Error loading protos from ${filename} (root: ${window.PROTO_ROOT})`;
|
||||
window.log.error(text);
|
||||
throw new Error(text);
|
||||
}
|
||||
|
|
|
@ -209,9 +209,7 @@ MessageSender.prototype = {
|
|||
}
|
||||
if (data.byteLength !== size) {
|
||||
throw new Error(
|
||||
`makeAttachmentPointer: Size ${size} did not match data.byteLength ${
|
||||
data.byteLength
|
||||
}`
|
||||
`makeAttachmentPointer: Size ${size} did not match data.byteLength ${data.byteLength}`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
* https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses
|
||||
*/
|
||||
|
||||
// prettier-ignore
|
||||
b64ToUint6(nChr) {
|
||||
return nChr > 64 && nChr < 91
|
||||
? nChr - 65
|
||||
|
@ -59,6 +60,7 @@
|
|||
return aBBytes;
|
||||
},
|
||||
|
||||
// prettier-ignore
|
||||
uint6ToB64(nUint6) {
|
||||
return nUint6 < 26
|
||||
? nUint6 + 65
|
||||
|
@ -82,7 +84,7 @@
|
|||
nIdx += 1
|
||||
) {
|
||||
nMod3 = nIdx % 3;
|
||||
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) {
|
||||
if (nIdx > 0 && ((nIdx * 4) / 3) % 76 === 0) {
|
||||
sB64Enc += '\r\n';
|
||||
}
|
||||
nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24);
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
receiver.addEventListener('groupsync', this.ongroup);
|
||||
|
||||
const ourNumber = textsecure.storage.user.getNumber();
|
||||
const { wrap, sendOptions } = ConversationController.prepareForSend(
|
||||
ourNumber,
|
||||
{ syncMessage: true }
|
||||
);
|
||||
const {
|
||||
wrap,
|
||||
sendOptions,
|
||||
} = ConversationController.prepareForSend(ourNumber, { syncMessage: true });
|
||||
|
||||
window.log.info('SyncRequest created. Sending config sync request...');
|
||||
wrap(sender.sendRequestConfigurationSyncMessage(sendOptions));
|
||||
|
|
2
main.js
2
main.js
|
@ -578,7 +578,7 @@ async function getIsLinked() {
|
|||
|
||||
let stickerCreatorWindow;
|
||||
async function showStickerCreator() {
|
||||
if (!await getIsLinked()) {
|
||||
if (!(await getIsLinked())) {
|
||||
const { message } = locale.messages[
|
||||
'StickerCreator--Authentication--error'
|
||||
];
|
||||
|
|
|
@ -224,7 +224,7 @@
|
|||
"npm-run-all": "4.1.5",
|
||||
"nyc": "11.4.1",
|
||||
"patch-package": "6.1.2",
|
||||
"prettier": "1.12.0",
|
||||
"prettier": "1.19.1",
|
||||
"react-docgen-typescript": "1.2.6",
|
||||
"react-styleguidist": "7.0.1",
|
||||
"sass-loader": "7.2.0",
|
||||
|
|
|
@ -45,19 +45,13 @@ export const AppStage = (props: Props) => {
|
|||
} = props;
|
||||
const i18n = useI18n();
|
||||
|
||||
const handleNext = React.useCallback(
|
||||
() => {
|
||||
const handleNext = React.useCallback(() => {
|
||||
history.push(next);
|
||||
},
|
||||
[next]
|
||||
);
|
||||
}, [next]);
|
||||
|
||||
const handlePrev = React.useCallback(
|
||||
() => {
|
||||
const handlePrev = React.useCallback(() => {
|
||||
history.push(prev);
|
||||
},
|
||||
[prev]
|
||||
);
|
||||
}, [prev]);
|
||||
|
||||
const addMoreCount = stickersDuck.useAddMoreCount();
|
||||
const toasts = stickersDuck.useToasts();
|
||||
|
|
|
@ -37,26 +37,17 @@ export const MetaStage = () => {
|
|||
accept: ['image/png', 'image/webp'],
|
||||
});
|
||||
|
||||
const onNext = React.useCallback(
|
||||
() => {
|
||||
const onNext = React.useCallback(() => {
|
||||
setConfirming(true);
|
||||
},
|
||||
[setConfirming]
|
||||
);
|
||||
}, [setConfirming]);
|
||||
|
||||
const onCancel = React.useCallback(
|
||||
() => {
|
||||
const onCancel = React.useCallback(() => {
|
||||
setConfirming(false);
|
||||
},
|
||||
[setConfirming]
|
||||
);
|
||||
}, [setConfirming]);
|
||||
|
||||
const onConfirm = React.useCallback(
|
||||
() => {
|
||||
const onConfirm = React.useCallback(() => {
|
||||
history.push('/upload');
|
||||
},
|
||||
[setConfirming]
|
||||
);
|
||||
}, [setConfirming]);
|
||||
|
||||
const coverFrameClass = isDragActive
|
||||
? styles.coverFrameActive
|
||||
|
|
|
@ -23,8 +23,7 @@ export const UploadStage = () => {
|
|||
const total = orderedData.length;
|
||||
const [complete, setComplete] = React.useState(0);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
const onProgress = () => setComplete(i => i + 1);
|
||||
try {
|
||||
|
@ -37,17 +36,13 @@ export const UploadStage = () => {
|
|||
actions.setPackMeta(packMeta);
|
||||
history.push('/share');
|
||||
} catch (e) {
|
||||
actions.addToast('StickerCreator--Toasts--errorUploading', [
|
||||
e.message,
|
||||
]);
|
||||
actions.addToast('StickerCreator--Toasts--errorUploading', [e.message]);
|
||||
history.push('/add-meta');
|
||||
}
|
||||
})();
|
||||
|
||||
return noop;
|
||||
},
|
||||
[title, author, cover, orderedData]
|
||||
);
|
||||
}, [title, author, cover, orderedData]);
|
||||
|
||||
return (
|
||||
<AppStage empty={true}>
|
||||
|
|
|
@ -12,8 +12,7 @@ export const ConfirmModal = React.memo(
|
|||
const [popperRoot, setPopperRoot] = React.useState<HTMLDivElement>();
|
||||
|
||||
// Create popper root and handle outside clicks
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const root = document.createElement('div');
|
||||
setPopperRoot(root);
|
||||
document.body.appendChild(root);
|
||||
|
@ -28,9 +27,7 @@ export const ConfirmModal = React.memo(
|
|||
document.body.removeChild(root);
|
||||
document.removeEventListener('click', handleOutsideClick);
|
||||
};
|
||||
},
|
||||
[onCancel]
|
||||
);
|
||||
}, [onCancel]);
|
||||
|
||||
return popperRoot
|
||||
? createPortal(
|
||||
|
|
|
@ -9,8 +9,9 @@ export type Props = {
|
|||
export const ShareButtons = React.memo(({ value }: Props) => {
|
||||
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 text = encodeURIComponent(
|
||||
`${i18n('StickerCreator--ShareStage--socialMessage')} ${value}`
|
||||
|
@ -46,9 +47,7 @@ export const ShareButtons = React.memo(({ value }: Props) => {
|
|||
`https://wa.me?text=${text}`,
|
||||
],
|
||||
];
|
||||
},
|
||||
[i18n, value]
|
||||
);
|
||||
}, [i18n, value]);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
|
|
|
@ -82,12 +82,9 @@ export const StickerFrame = React.memo(
|
|||
] = React.useState<HTMLElement | null>(null);
|
||||
const timerRef = React.useRef<number>();
|
||||
|
||||
const handleToggleEmojiPicker = React.useCallback(
|
||||
() => {
|
||||
const handleToggleEmojiPicker = React.useCallback(() => {
|
||||
setEmojiPickerOpen(open => !open);
|
||||
},
|
||||
[setEmojiPickerOpen]
|
||||
);
|
||||
}, [setEmojiPickerOpen]);
|
||||
|
||||
const handlePickEmoji = React.useCallback(
|
||||
(emoji: EmojiPickDataType) => {
|
||||
|
@ -97,30 +94,21 @@ export const StickerFrame = React.memo(
|
|||
[id, onPickEmoji, setEmojiPickerOpen]
|
||||
);
|
||||
|
||||
const handleRemove = React.useCallback(
|
||||
() => {
|
||||
const handleRemove = React.useCallback(() => {
|
||||
onRemove(id);
|
||||
},
|
||||
[onRemove, id]
|
||||
);
|
||||
}, [onRemove, id]);
|
||||
|
||||
const handleMouseEnter = React.useCallback(
|
||||
() => {
|
||||
const handleMouseEnter = React.useCallback(() => {
|
||||
window.clearTimeout(timerRef.current);
|
||||
timerRef.current = window.setTimeout(() => {
|
||||
setPreviewActive(true);
|
||||
}, 500);
|
||||
},
|
||||
[timerRef, setPreviewActive]
|
||||
);
|
||||
}, [timerRef, setPreviewActive]);
|
||||
|
||||
const handleMouseLeave = React.useCallback(
|
||||
() => {
|
||||
const handleMouseLeave = React.useCallback(() => {
|
||||
clearTimeout(timerRef.current);
|
||||
setPreviewActive(false);
|
||||
},
|
||||
[timerRef, setPreviewActive]
|
||||
);
|
||||
}, [timerRef, setPreviewActive]);
|
||||
|
||||
React.useEffect(
|
||||
() => () => {
|
||||
|
@ -130,8 +118,7 @@ export const StickerFrame = React.memo(
|
|||
);
|
||||
|
||||
// Create popper root and handle outside clicks
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (emojiPickerOpen) {
|
||||
const root = document.createElement('div');
|
||||
setEmojiPopperRoot(root);
|
||||
|
@ -150,12 +137,9 @@ export const StickerFrame = React.memo(
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[emojiPickerOpen, setEmojiPickerOpen, setEmojiPopperRoot]
|
||||
);
|
||||
}, [emojiPickerOpen, setEmojiPickerOpen, setEmojiPopperRoot]);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (mode !== 'pick-emoji' && image && previewActive) {
|
||||
const root = document.createElement('div');
|
||||
setPreviewPopperRoot(root);
|
||||
|
@ -167,9 +151,7 @@ export const StickerFrame = React.memo(
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[mode, image, previewActive, setPreviewPopperRoot]
|
||||
);
|
||||
}, [mode, image, previewActive, setPreviewPopperRoot]);
|
||||
|
||||
const [dragActive, setDragActive] = React.useState<boolean>(false);
|
||||
const containerClass = dragActive ? styles.dragActive : styles.container;
|
||||
|
|
|
@ -12,8 +12,7 @@ const DEFAULT_DISMISS = 1e4;
|
|||
export const Toaster = React.memo(({ loaf, onDismiss, className }: Props) => {
|
||||
const slice = last(loaf);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (!slice) {
|
||||
return noop;
|
||||
}
|
||||
|
@ -25,9 +24,7 @@ export const Toaster = React.memo(({ loaf, onDismiss, className }: Props) => {
|
|||
return () => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
},
|
||||
[slice, onDismiss]
|
||||
);
|
||||
}, [slice, onDismiss]);
|
||||
|
||||
if (!slice) {
|
||||
return null;
|
||||
|
|
|
@ -12,15 +12,12 @@ export type Props = {
|
|||
|
||||
export const CopyText = React.memo(({ label, onCopy, value }: Props) => {
|
||||
const i18n = useI18n();
|
||||
const handleClick = React.useCallback(
|
||||
() => {
|
||||
const handleClick = React.useCallback(() => {
|
||||
copy(value);
|
||||
if (onCopy) {
|
||||
onCopy();
|
||||
}
|
||||
},
|
||||
[onCopy, value]
|
||||
);
|
||||
}, [onCopy, value]);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
|
|
|
@ -37,14 +37,11 @@ export const DropZone = (props: Props) => {
|
|||
accept: ['image/png', 'image/webp'],
|
||||
});
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (onDragActive) {
|
||||
onDragActive(isDragActive);
|
||||
}
|
||||
},
|
||||
[isDragActive, onDragActive]
|
||||
);
|
||||
}, [isDragActive, onDragActive]);
|
||||
|
||||
return (
|
||||
<div {...getRootProps({ className: getClassName(props, isDragActive) })}>
|
||||
|
|
|
@ -16,12 +16,9 @@ const checkSvg = (
|
|||
|
||||
export const LabeledCheckbox = React.memo(
|
||||
({ children, value, onChange }: Props) => {
|
||||
const handleChange = React.useCallback(
|
||||
() => {
|
||||
const handleChange = React.useCallback(() => {
|
||||
onChange(!value);
|
||||
},
|
||||
[onChange, value]
|
||||
);
|
||||
}, [onChange, value]);
|
||||
|
||||
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={styles.bar}
|
||||
style={{ width: `${Math.floor(count / total * 100)}%` }}
|
||||
style={{ width: `${Math.floor((count / total) * 100)}%` }}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
|
|
|
@ -136,7 +136,7 @@ $conversation-colors: (
|
|||
'teal': $color-conversation-teal,
|
||||
'green': $color-conversation-green,
|
||||
'light_green': $color-conversation-light_green,
|
||||
'blue_grey': $color-conversation-blue_grey
|
||||
'blue_grey': $color-conversation-blue_grey,
|
||||
);
|
||||
$conversation-colors-tint: (
|
||||
'red': $color-conversation-red-tint,
|
||||
|
@ -149,7 +149,7 @@ $conversation-colors-tint: (
|
|||
'teal': $color-conversation-teal-tint,
|
||||
'green': $color-conversation-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: (
|
||||
'red': $color-conversation-red-shade,
|
||||
|
@ -162,7 +162,7 @@ $conversation-colors-shade: (
|
|||
'teal': $color-conversation-teal-shade,
|
||||
'green': $color-conversation-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
|
||||
|
|
|
@ -111,15 +111,12 @@ export const CompositionArea = ({
|
|||
const editorRef = React.useRef<Editor>(null);
|
||||
const inputApiRef = React.useRef<InputApi | undefined>();
|
||||
|
||||
const handleForceSend = React.useCallback(
|
||||
() => {
|
||||
const handleForceSend = React.useCallback(() => {
|
||||
setLarge(false);
|
||||
if (inputApiRef.current) {
|
||||
inputApiRef.current.submit();
|
||||
}
|
||||
},
|
||||
[inputApiRef, setLarge]
|
||||
);
|
||||
}, [inputApiRef, setLarge]);
|
||||
|
||||
const handleSubmit = React.useCallback<typeof onSubmit>(
|
||||
(...args) => {
|
||||
|
@ -129,14 +126,11 @@ export const CompositionArea = ({
|
|||
[setLarge, onSubmit]
|
||||
);
|
||||
|
||||
const focusInput = React.useCallback(
|
||||
() => {
|
||||
const focusInput = React.useCallback(() => {
|
||||
if (editorRef.current) {
|
||||
editorRef.current.focus();
|
||||
}
|
||||
},
|
||||
[editorRef]
|
||||
);
|
||||
}, [editorRef]);
|
||||
|
||||
const withStickers =
|
||||
countStickers({
|
||||
|
@ -180,18 +174,14 @@ export const CompositionArea = ({
|
|||
[inputApiRef, onPickEmoji]
|
||||
);
|
||||
|
||||
const handleToggleLarge = React.useCallback(
|
||||
() => {
|
||||
const handleToggleLarge = React.useCallback(() => {
|
||||
setLarge(l => !l);
|
||||
},
|
||||
[setLarge]
|
||||
);
|
||||
}, [setLarge]);
|
||||
|
||||
// The following is a work-around to allow react to lay-out backbone-managed
|
||||
// dom nodes until those functions are in React
|
||||
const micCellRef = React.useRef<HTMLDivElement>(null);
|
||||
React.useLayoutEffect(
|
||||
() => {
|
||||
React.useLayoutEffect(() => {
|
||||
const { current: micCellContainer } = micCellRef;
|
||||
if (micCellContainer && micCellEl) {
|
||||
emptyElement(micCellContainer);
|
||||
|
@ -199,21 +189,16 @@ export const CompositionArea = ({
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[micCellRef, micCellEl, large, dirty, showMic]
|
||||
);
|
||||
}, [micCellRef, micCellEl, large, dirty, showMic]);
|
||||
|
||||
React.useLayoutEffect(
|
||||
() => {
|
||||
React.useLayoutEffect(() => {
|
||||
const { current: attSlot } = attSlotRef;
|
||||
if (attSlot && attachmentListEl) {
|
||||
attSlot.appendChild(attachmentListEl);
|
||||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[attSlotRef, attachmentListEl]
|
||||
);
|
||||
}, [attSlotRef, attachmentListEl]);
|
||||
|
||||
const emojiButtonFragment = (
|
||||
<div className="module-composition-area__button-cell">
|
||||
|
@ -287,8 +272,7 @@ export const CompositionArea = ({
|
|||
) : null;
|
||||
|
||||
// Listen for cmd/ctrl-shift-x to toggle large composition mode
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handler = (e: KeyboardEvent) => {
|
||||
const { key, shiftKey, ctrlKey, metaKey } = e;
|
||||
// When using the ctrl key, `key` is `'X'`. When using the cmd key, `key` is `'x'`
|
||||
|
@ -309,9 +293,7 @@ export const CompositionArea = ({
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handler);
|
||||
};
|
||||
},
|
||||
[setLarge]
|
||||
);
|
||||
}, [setLarge]);
|
||||
|
||||
return (
|
||||
<div className="module-composition-area">
|
||||
|
|
|
@ -307,14 +307,11 @@ export const CompositionInput = ({
|
|||
[onDirtyChange, onEditorStateChange, editorStateRef]
|
||||
);
|
||||
|
||||
const resetEmojiResults = React.useCallback(
|
||||
() => {
|
||||
const resetEmojiResults = React.useCallback(() => {
|
||||
setEmojiResults([]);
|
||||
setEmojiResultsIndex(0);
|
||||
setSearchText('');
|
||||
},
|
||||
[setEmojiResults, setEmojiResultsIndex, setSearchText]
|
||||
);
|
||||
}, [setEmojiResults, setEmojiResultsIndex, setSearchText]);
|
||||
|
||||
const handleEditorStateChange = React.useCallback(
|
||||
(newState: EditorState) => {
|
||||
|
@ -361,8 +358,7 @@ export const CompositionInput = ({
|
|||
]
|
||||
);
|
||||
|
||||
const handleBeforeInput = React.useCallback(
|
||||
(): DraftHandleValue => {
|
||||
const handleBeforeInput = React.useCallback((): DraftHandleValue => {
|
||||
if (!editorStateRef.current) {
|
||||
return 'not-handled';
|
||||
}
|
||||
|
@ -378,9 +374,7 @@ export const CompositionInput = ({
|
|||
}
|
||||
|
||||
return 'not-handled';
|
||||
},
|
||||
[onTextTooLong, editorStateRef]
|
||||
);
|
||||
}, [onTextTooLong, editorStateRef]);
|
||||
|
||||
const handlePastedText = React.useCallback(
|
||||
(pastedText: string): DraftHandleValue => {
|
||||
|
@ -406,25 +400,19 @@ export const CompositionInput = ({
|
|||
[onTextTooLong, editorStateRef]
|
||||
);
|
||||
|
||||
const resetEditorState = React.useCallback(
|
||||
() => {
|
||||
const resetEditorState = React.useCallback(() => {
|
||||
const newEmptyState = EditorState.createEmpty(compositeDecorator);
|
||||
setAndTrackEditorState(newEmptyState);
|
||||
resetEmojiResults();
|
||||
},
|
||||
[editorStateRef, resetEmojiResults, setAndTrackEditorState]
|
||||
);
|
||||
}, [editorStateRef, resetEmojiResults, setAndTrackEditorState]);
|
||||
|
||||
const submit = React.useCallback(
|
||||
() => {
|
||||
const submit = React.useCallback(() => {
|
||||
const { current: state } = editorStateRef;
|
||||
const text = state.getCurrentContent().getPlainText();
|
||||
const emojidText = replaceColons(text);
|
||||
const trimmedText = emojidText.trim();
|
||||
onSubmit(trimmedText);
|
||||
},
|
||||
[editorStateRef, onSubmit]
|
||||
);
|
||||
}, [editorStateRef, onSubmit]);
|
||||
|
||||
const handleEditorSizeChange = React.useCallback(
|
||||
(rect: ContentRect) => {
|
||||
|
@ -716,8 +704,7 @@ export const CompositionInput = ({
|
|||
);
|
||||
|
||||
// Create popper root
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (emojiResults.length > 0) {
|
||||
const root = document.createElement('div');
|
||||
setPopperRoot(root);
|
||||
|
@ -730,31 +717,22 @@ export const CompositionInput = ({
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[setPopperRoot, emojiResults]
|
||||
);
|
||||
}, [setPopperRoot, emojiResults]);
|
||||
|
||||
const onFocus = React.useCallback(
|
||||
() => {
|
||||
const onFocus = React.useCallback(() => {
|
||||
focusRef.current = true;
|
||||
},
|
||||
[focusRef]
|
||||
);
|
||||
}, [focusRef]);
|
||||
|
||||
const onBlur = React.useCallback(
|
||||
() => {
|
||||
const onBlur = React.useCallback(() => {
|
||||
focusRef.current = false;
|
||||
},
|
||||
[focusRef]
|
||||
);
|
||||
}, [focusRef]);
|
||||
|
||||
// Manage 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)
|
||||
// This needs to be done in an effect because React doesn't support focus{In,Out}
|
||||
// https://github.com/facebook/react/issues/6410
|
||||
React.useLayoutEffect(
|
||||
() => {
|
||||
React.useLayoutEffect(() => {
|
||||
const { current: rootEl } = rootElRef;
|
||||
|
||||
if (rootEl) {
|
||||
|
@ -774,9 +752,7 @@ export const CompositionInput = ({
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[editorStateRef, rootElRef, setAndTrackEditorState]
|
||||
);
|
||||
}, [editorStateRef, rootElRef, setAndTrackEditorState]);
|
||||
|
||||
if (inputApi) {
|
||||
inputApi.current = {
|
||||
|
@ -843,9 +819,7 @@ export const CompositionInput = ({
|
|||
}}
|
||||
role="listbox"
|
||||
aria-expanded={true}
|
||||
aria-activedescendant={`emoji-result--${
|
||||
emojiResults[emojiResultsIndex].short_name
|
||||
}`}
|
||||
aria-activedescendant={`emoji-result--${emojiResults[emojiResultsIndex].short_name}`}
|
||||
>
|
||||
{emojiResults.map((emoji, index) => (
|
||||
<button
|
||||
|
|
|
@ -30,8 +30,7 @@ export const ConfirmationDialog = React.memo(
|
|||
affirmativeText,
|
||||
negativeText,
|
||||
}: Props) => {
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handler = ({ key }: KeyboardEvent) => {
|
||||
if (key === 'Escape') {
|
||||
onClose();
|
||||
|
@ -42,9 +41,7 @@ export const ConfirmationDialog = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handler);
|
||||
};
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
}, [onClose]);
|
||||
|
||||
const handleCancel = React.useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
|
@ -55,25 +52,19 @@ export const ConfirmationDialog = React.memo(
|
|||
[onClose]
|
||||
);
|
||||
|
||||
const handleNegative = React.useCallback(
|
||||
() => {
|
||||
const handleNegative = React.useCallback(() => {
|
||||
onClose();
|
||||
if (onNegative) {
|
||||
onNegative();
|
||||
}
|
||||
},
|
||||
[onClose, onNegative]
|
||||
);
|
||||
}, [onClose, onNegative]);
|
||||
|
||||
const handleAffirmative = React.useCallback(
|
||||
() => {
|
||||
const handleAffirmative = React.useCallback(() => {
|
||||
onClose();
|
||||
if (onAffirmative) {
|
||||
onAffirmative();
|
||||
}
|
||||
},
|
||||
[onClose, onAffirmative]
|
||||
);
|
||||
}, [onClose, onAffirmative]);
|
||||
|
||||
return (
|
||||
<div className="module-confirmation-dialog__container">
|
||||
|
|
|
@ -39,8 +39,7 @@ export const ConfirmationModal = React.memo(
|
|||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handler = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
onClose();
|
||||
|
@ -54,9 +53,7 @@ export const ConfirmationModal = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handler);
|
||||
};
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
}, [onClose]);
|
||||
|
||||
const handleCancel = React.useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
|
|
|
@ -195,9 +195,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
|||
<div
|
||||
className={classNames(
|
||||
'module-conversation-list-item__message__status-icon',
|
||||
`module-conversation-list-item__message__status-icon--${
|
||||
lastMessage.status
|
||||
}`
|
||||
`module-conversation-list-item__message__status-icon--${lastMessage.status}`
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -23,9 +23,11 @@ interface Props {
|
|||
close: () => void;
|
||||
i18n: LocalizerType;
|
||||
media: Array<MediaItemType>;
|
||||
onSave?: (
|
||||
options: { attachment: AttachmentType; message: Message; index: number }
|
||||
) => void;
|
||||
onSave?: (options: {
|
||||
attachment: AttachmentType;
|
||||
message: Message;
|
||||
index: number;
|
||||
}) => void;
|
||||
selectedIndex: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,29 +110,24 @@ export type PropsActions = {
|
|||
showMessageDetail: (id: string) => void;
|
||||
|
||||
openConversation: (conversationId: string, messageId?: string) => void;
|
||||
showContactDetail: (
|
||||
options: { contact: ContactType; signalAccount?: string }
|
||||
) => void;
|
||||
showContactDetail: (options: {
|
||||
contact: ContactType;
|
||||
signalAccount?: string;
|
||||
}) => void;
|
||||
|
||||
showVisualAttachment: (
|
||||
options: { attachment: AttachmentType; messageId: string }
|
||||
) => void;
|
||||
downloadAttachment: (
|
||||
options: {
|
||||
showVisualAttachment: (options: {
|
||||
attachment: AttachmentType;
|
||||
messageId: string;
|
||||
}) => void;
|
||||
downloadAttachment: (options: {
|
||||
attachment: AttachmentType;
|
||||
timestamp: number;
|
||||
isDangerous: boolean;
|
||||
}
|
||||
) => void;
|
||||
}) => void;
|
||||
displayTapToViewMessage: (messageId: string) => unknown;
|
||||
|
||||
openLink: (url: string) => void;
|
||||
scrollToQuotedMessage: (
|
||||
options: {
|
||||
author: string;
|
||||
sentAt: number;
|
||||
}
|
||||
) => void;
|
||||
scrollToQuotedMessage: (options: { author: string; sentAt: number }) => void;
|
||||
selectMessage?: (messageId: string, conversationId: string) => unknown;
|
||||
};
|
||||
|
||||
|
|
|
@ -37,27 +37,20 @@ export const EmojiButton = React.memo(
|
|||
null
|
||||
);
|
||||
|
||||
const handleClickButton = React.useCallback(
|
||||
() => {
|
||||
const handleClickButton = React.useCallback(() => {
|
||||
if (popperRoot) {
|
||||
setOpen(false);
|
||||
} else {
|
||||
setOpen(true);
|
||||
}
|
||||
},
|
||||
[popperRoot, setOpen]
|
||||
);
|
||||
}, [popperRoot, setOpen]);
|
||||
|
||||
const handleClose = React.useCallback(
|
||||
() => {
|
||||
const handleClose = React.useCallback(() => {
|
||||
setOpen(false);
|
||||
},
|
||||
[setOpen]
|
||||
);
|
||||
}, [setOpen]);
|
||||
|
||||
// Create popper root and handle outside clicks
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (open) {
|
||||
const root = document.createElement('div');
|
||||
setPopperRoot(root);
|
||||
|
@ -77,13 +70,10 @@ export const EmojiButton = React.memo(
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[open, setOpen, setPopperRoot]
|
||||
);
|
||||
}, [open, setOpen, setPopperRoot]);
|
||||
|
||||
// Install keyboard shortcut to open emoji picker
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
const { ctrlKey, key, metaKey, shiftKey } = event;
|
||||
const commandKey = get(window, 'platform') === 'darwin' && metaKey;
|
||||
|
@ -108,9 +98,7 @@ export const EmojiButton = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
};
|
||||
},
|
||||
[open, setOpen]
|
||||
);
|
||||
}, [open, setOpen]);
|
||||
|
||||
return (
|
||||
<Manager>
|
||||
|
|
|
@ -82,14 +82,11 @@ export const EmojiPicker = React.memo(
|
|||
const [scrollToRow, setScrollToRow] = React.useState(0);
|
||||
const [selectedTone, setSelectedTone] = React.useState(skinTone);
|
||||
|
||||
const handleToggleSearch = React.useCallback(
|
||||
() => {
|
||||
const handleToggleSearch = React.useCallback(() => {
|
||||
setSearchText('');
|
||||
setSelectedCategory(categories[0]);
|
||||
setSearchMode(m => !m);
|
||||
},
|
||||
[setSearchText, setSearchMode]
|
||||
);
|
||||
}, [setSearchText, setSearchMode]);
|
||||
|
||||
const debounceSearchChange = React.useMemo(
|
||||
() =>
|
||||
|
@ -141,8 +138,7 @@ export const EmojiPicker = React.memo(
|
|||
);
|
||||
|
||||
// Handle escape key
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handler = (event: KeyboardEvent) => {
|
||||
if (searchMode && event.key === 'Escape') {
|
||||
setSearchText('');
|
||||
|
@ -175,9 +171,7 @@ export const EmojiPicker = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handler);
|
||||
};
|
||||
},
|
||||
[onClose, searchMode]
|
||||
);
|
||||
}, [onClose, searchMode]);
|
||||
|
||||
// Restore focus on teardown
|
||||
React.useEffect(() => {
|
||||
|
@ -193,25 +187,27 @@ export const EmojiPicker = React.memo(
|
|||
};
|
||||
}, []);
|
||||
|
||||
const emojiGrid = React.useMemo(
|
||||
() => {
|
||||
const emojiGrid = React.useMemo(() => {
|
||||
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 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];
|
||||
},
|
||||
[dataByCategory, categories, firstRecent, searchText]
|
||||
);
|
||||
}, [dataByCategory, categories, firstRecent, searchText]);
|
||||
|
||||
const catRowEnds = React.useMemo(
|
||||
() => {
|
||||
const catRowEnds = React.useMemo(() => {
|
||||
const rowEnds: Array<number> = [
|
||||
Math.ceil(firstRecent.length / COL_COUNT) - 1,
|
||||
];
|
||||
|
@ -225,18 +221,13 @@ export const EmojiPicker = React.memo(
|
|||
});
|
||||
|
||||
return rowEnds;
|
||||
},
|
||||
[categories, dataByCategory]
|
||||
);
|
||||
}, [categories, dataByCategory]);
|
||||
|
||||
const catToRowOffsets = React.useMemo(
|
||||
() => {
|
||||
const catToRowOffsets = React.useMemo(() => {
|
||||
const offsets = initial(catRowEnds).map(i => i + 1);
|
||||
|
||||
return zipObject(categories, [0, ...offsets]);
|
||||
},
|
||||
[categories, catRowEnds]
|
||||
);
|
||||
}, [categories, catRowEnds]);
|
||||
|
||||
const catOffsetEntries = React.useMemo(
|
||||
() => Object.entries(catToRowOffsets),
|
||||
|
@ -331,8 +322,7 @@ export const EmojiPicker = React.memo(
|
|||
/>
|
||||
</div>
|
||||
) : (
|
||||
categories.map(
|
||||
cat =>
|
||||
categories.map(cat =>
|
||||
cat === 'recents' && firstRecent.length === 0 ? null : (
|
||||
<button
|
||||
key={cat}
|
||||
|
|
|
@ -52,8 +52,7 @@ export const StickerButton = React.memo(
|
|||
null
|
||||
);
|
||||
|
||||
const handleClickButton = React.useCallback(
|
||||
() => {
|
||||
const handleClickButton = React.useCallback(() => {
|
||||
// Clear tooltip state
|
||||
clearInstalledStickerPack();
|
||||
clearShowIntroduction();
|
||||
|
@ -66,15 +65,13 @@ export const StickerButton = React.memo(
|
|||
} else {
|
||||
setOpen(true);
|
||||
}
|
||||
},
|
||||
[
|
||||
}, [
|
||||
clearInstalledStickerPack,
|
||||
onClickAddPack,
|
||||
installedPacks,
|
||||
popperRoot,
|
||||
setOpen,
|
||||
]
|
||||
);
|
||||
]);
|
||||
|
||||
const handlePickSticker = React.useCallback(
|
||||
(packId: string, stickerId: number) => {
|
||||
|
@ -84,44 +81,32 @@ export const StickerButton = React.memo(
|
|||
[setOpen, onPickSticker]
|
||||
);
|
||||
|
||||
const handleClose = React.useCallback(
|
||||
() => {
|
||||
const handleClose = React.useCallback(() => {
|
||||
setOpen(false);
|
||||
},
|
||||
[setOpen]
|
||||
);
|
||||
}, [setOpen]);
|
||||
|
||||
const handleClickAddPack = React.useCallback(
|
||||
() => {
|
||||
const handleClickAddPack = React.useCallback(() => {
|
||||
setOpen(false);
|
||||
if (showPickerHint) {
|
||||
clearShowPickerHint();
|
||||
}
|
||||
onClickAddPack();
|
||||
},
|
||||
[onClickAddPack, showPickerHint, clearShowPickerHint]
|
||||
);
|
||||
}, [onClickAddPack, showPickerHint, clearShowPickerHint]);
|
||||
|
||||
const handleClearIntroduction = React.useCallback(
|
||||
() => {
|
||||
const handleClearIntroduction = React.useCallback(() => {
|
||||
clearInstalledStickerPack();
|
||||
clearShowIntroduction();
|
||||
},
|
||||
[clearInstalledStickerPack, clearShowIntroduction]
|
||||
);
|
||||
}, [clearInstalledStickerPack, clearShowIntroduction]);
|
||||
|
||||
// Create popper root and handle outside clicks
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (open) {
|
||||
const root = document.createElement('div');
|
||||
setPopperRoot(root);
|
||||
document.body.appendChild(root);
|
||||
const handleOutsideClick = ({ target }: MouseEvent) => {
|
||||
const targetElement = target as HTMLElement;
|
||||
const className = targetElement
|
||||
? targetElement.className || ''
|
||||
: '';
|
||||
const className = targetElement ? targetElement.className || '' : '';
|
||||
|
||||
// We need to special-case sticker picker header buttons, because they can
|
||||
// disappear after being clicked, which breaks the .contains() check below.
|
||||
|
@ -143,13 +128,10 @@ export const StickerButton = React.memo(
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[open, setOpen, setPopperRoot]
|
||||
);
|
||||
}, [open, setOpen, setPopperRoot]);
|
||||
|
||||
// Install keyboard shortcut to open sticker picker
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
const { ctrlKey, key, metaKey, shiftKey } = event;
|
||||
const commandKey = get(window, 'platform') === 'darwin' && metaKey;
|
||||
|
@ -174,13 +156,10 @@ export const StickerButton = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
};
|
||||
},
|
||||
[open, setOpen]
|
||||
);
|
||||
}, [open, setOpen]);
|
||||
|
||||
// Clear the installed pack after one minute
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (installedPack) {
|
||||
// tslint:disable-next-line:no-string-based-set-timeout
|
||||
const timerId = setTimeout(clearInstalledStickerPack, 10 * 1000);
|
||||
|
@ -191,9 +170,7 @@ export const StickerButton = React.memo(
|
|||
}
|
||||
|
||||
return noop;
|
||||
},
|
||||
[installedPack, clearInstalledStickerPack]
|
||||
);
|
||||
}, [installedPack, clearInstalledStickerPack]);
|
||||
|
||||
if (
|
||||
countStickers({
|
||||
|
|
|
@ -53,12 +53,9 @@ export const StickerManager = React.memo(
|
|||
});
|
||||
}, []);
|
||||
|
||||
const clearPackToPreview = React.useCallback(
|
||||
() => {
|
||||
const clearPackToPreview = React.useCallback(() => {
|
||||
setPackToPreview(null);
|
||||
},
|
||||
[setPackToPreview]
|
||||
);
|
||||
}, [setPackToPreview]);
|
||||
|
||||
const previewPack = React.useCallback(
|
||||
(pack: StickerPackType) => {
|
||||
|
|
|
@ -26,12 +26,9 @@ export const StickerManagerPackRow = React.memo(
|
|||
const { id, key, isBlessed } = pack;
|
||||
const [uninstalling, setUninstalling] = React.useState(false);
|
||||
|
||||
const clearUninstalling = React.useCallback(
|
||||
() => {
|
||||
const clearUninstalling = React.useCallback(() => {
|
||||
setUninstalling(false);
|
||||
},
|
||||
[setUninstalling]
|
||||
);
|
||||
}, [setUninstalling]);
|
||||
|
||||
const handleInstall = React.useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
|
@ -55,15 +52,12 @@ export const StickerManagerPackRow = React.memo(
|
|||
[setUninstalling, id, key, isBlessed]
|
||||
);
|
||||
|
||||
const handleConfirmUninstall = React.useCallback(
|
||||
() => {
|
||||
const handleConfirmUninstall = React.useCallback(() => {
|
||||
clearUninstalling();
|
||||
if (uninstallStickerPack) {
|
||||
uninstallStickerPack(id, key);
|
||||
}
|
||||
},
|
||||
[id, key, clearUninstalling]
|
||||
);
|
||||
}, [id, key, clearUninstalling]);
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(event: React.KeyboardEvent) => {
|
||||
|
|
|
@ -42,7 +42,7 @@ function getPacksPageOffset(page: number, packs: number): number {
|
|||
if (isLastPacksPage(page, packs)) {
|
||||
return (
|
||||
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 {
|
||||
stickers = recentStickers,
|
||||
title: packTitle = 'Recent Stickers',
|
||||
} =
|
||||
selectedPack || {};
|
||||
} = selectedPack || {};
|
||||
|
||||
const [isUsingKeyboard, setIsUsingKeyboard] = React.useState(false);
|
||||
const [packsPage, setPacksPage] = React.useState(0);
|
||||
const onClickPrevPackPage = React.useCallback(
|
||||
() => {
|
||||
const onClickPrevPackPage = React.useCallback(() => {
|
||||
setPacksPage(i => i - 1);
|
||||
},
|
||||
[setPacksPage]
|
||||
);
|
||||
const onClickNextPackPage = React.useCallback(
|
||||
() => {
|
||||
}, [setPacksPage]);
|
||||
const onClickNextPackPage = React.useCallback(() => {
|
||||
setPacksPage(i => i + 1);
|
||||
},
|
||||
[setPacksPage]
|
||||
);
|
||||
}, [setPacksPage]);
|
||||
|
||||
// Handle escape key
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handler = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Tab') {
|
||||
// We do NOT prevent default here to allow Tab to be used normally
|
||||
|
@ -127,9 +119,7 @@ export const StickerPicker = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handler);
|
||||
};
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
}, [onClose]);
|
||||
|
||||
// Focus popup on after initial render, restore focus on teardown
|
||||
React.useEffect(() => {
|
||||
|
|
|
@ -79,8 +79,7 @@ export const StickerPreviewModal = React.memo(
|
|||
const [confirmingUninstall, setConfirmingUninstall] = React.useState(false);
|
||||
|
||||
// Restore focus on teardown
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
@ -95,9 +94,7 @@ export const StickerPreviewModal = React.memo(
|
|||
lastFocused.focus();
|
||||
}
|
||||
};
|
||||
},
|
||||
[root]
|
||||
);
|
||||
}, [root]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const div = document.createElement('div');
|
||||
|
@ -126,8 +123,7 @@ export const StickerPreviewModal = React.memo(
|
|||
}, []);
|
||||
|
||||
const isInstalled = Boolean(pack && pack.status === 'installed');
|
||||
const handleToggleInstall = React.useCallback(
|
||||
() => {
|
||||
const handleToggleInstall = React.useCallback(() => {
|
||||
if (!pack) {
|
||||
return;
|
||||
}
|
||||
|
@ -140,24 +136,24 @@ export const StickerPreviewModal = React.memo(
|
|||
installStickerPack(pack.id, pack.key);
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[isInstalled, pack, setConfirmingUninstall, installStickerPack, onClose]
|
||||
);
|
||||
}, [
|
||||
isInstalled,
|
||||
pack,
|
||||
setConfirmingUninstall,
|
||||
installStickerPack,
|
||||
onClose,
|
||||
]);
|
||||
|
||||
const handleUninstall = React.useCallback(
|
||||
() => {
|
||||
const handleUninstall = React.useCallback(() => {
|
||||
if (!pack) {
|
||||
return;
|
||||
}
|
||||
uninstallStickerPack(pack.id, pack.key);
|
||||
setConfirmingUninstall(false);
|
||||
// onClose is called by the confirmation modal
|
||||
},
|
||||
[uninstallStickerPack, setConfirmingUninstall, pack]
|
||||
);
|
||||
}, [uninstallStickerPack, setConfirmingUninstall, pack]);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
React.useEffect(() => {
|
||||
const handler = ({ key }: KeyboardEvent) => {
|
||||
if (key === 'Escape') {
|
||||
onClose();
|
||||
|
@ -169,9 +165,7 @@ export const StickerPreviewModal = React.memo(
|
|||
return () => {
|
||||
document.removeEventListener('keydown', handler);
|
||||
};
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
}, [onClose]);
|
||||
|
||||
const handleClickToClose = React.useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
export type RenderTextCallbackType = (
|
||||
options: {
|
||||
export type RenderTextCallbackType = (options: {
|
||||
text: string;
|
||||
key: number;
|
||||
}
|
||||
) => JSX.Element | string;
|
||||
}) => JSX.Element | string;
|
||||
|
||||
export type LocalizerType = (key: string, values?: Array<string>) => string;
|
||||
|
||||
|
|
|
@ -9234,9 +9234,9 @@
|
|||
"rule": "React-createRef",
|
||||
"path": "ts/components/conversation/Message.tsx",
|
||||
"line": " public focusRef: React.RefObject<HTMLDivElement> = React.createRef();",
|
||||
"lineNumber": 155,
|
||||
"lineNumber": 150,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2019-11-01T22:46:33.013Z",
|
||||
"updated": "2020-01-06T17:05:33.013Z",
|
||||
"reasonDetail": "Used for setting focus only"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ export function getTimerBucket(expiration: number, length: number): string {
|
|||
return '60';
|
||||
}
|
||||
|
||||
const bucket = Math.round(delta / length * 12);
|
||||
const bucket = Math.round((delta / length) * 12);
|
||||
|
||||
return padStart(String(bucket * 5), 2, '0');
|
||||
}
|
||||
|
|
|
@ -12527,9 +12527,10 @@ preserve@^0.2.0:
|
|||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
prettier@1.12.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.0.tgz#d26fc5894b9230de97629b39cae225b503724ce8"
|
||||
prettier@1.19.1:
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
||||
|
||||
pretty-bytes@^1.0.2:
|
||||
version "1.0.4"
|
||||
|
|
Loading…
Reference in a new issue