From 59636aaf94f2a657327105eaf733c42b9751a64d Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Wed, 12 May 2021 21:54:20 -0400 Subject: [PATCH 01/36] Add react-meteor-accounts --- packages/react-meteor-accounts/.gitignore | 1 + packages/react-meteor-accounts/.meteorignore | 3 + packages/react-meteor-accounts/README.md | 4 + .../react-meteor-accounts/package-lock.json | 486 ++++++++++++++++++ packages/react-meteor-accounts/package.js | 17 + packages/react-meteor-accounts/package.json | 15 + .../react-meteor-accounts/react-accounts.tsx | 43 ++ .../types/react-accounts.d.ts | 6 + 8 files changed, 575 insertions(+) create mode 100644 packages/react-meteor-accounts/.gitignore create mode 100644 packages/react-meteor-accounts/.meteorignore create mode 100644 packages/react-meteor-accounts/README.md create mode 100644 packages/react-meteor-accounts/package-lock.json create mode 100644 packages/react-meteor-accounts/package.js create mode 100644 packages/react-meteor-accounts/package.json create mode 100644 packages/react-meteor-accounts/react-accounts.tsx create mode 100644 packages/react-meteor-accounts/types/react-accounts.d.ts diff --git a/packages/react-meteor-accounts/.gitignore b/packages/react-meteor-accounts/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/packages/react-meteor-accounts/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/react-meteor-accounts/.meteorignore b/packages/react-meteor-accounts/.meteorignore new file mode 100644 index 00000000..f71737da --- /dev/null +++ b/packages/react-meteor-accounts/.meteorignore @@ -0,0 +1,3 @@ +node_modules +package.json +package-lock.json diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md new file mode 100644 index 00000000..fe22d5de --- /dev/null +++ b/packages/react-meteor-accounts/README.md @@ -0,0 +1,4 @@ +meteor/react-accounts +===================== + +A couple of simple hooks for accessing Meteor Accounts state. diff --git a/packages/react-meteor-accounts/package-lock.json b/packages/react-meteor-accounts/package-lock.json new file mode 100644 index 00000000..b4ae92e5 --- /dev/null +++ b/packages/react-meteor-accounts/package-lock.json @@ -0,0 +1,486 @@ +{ + "name": "meteor-react-accounts", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@babel/runtime": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", + "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.1.tgz", + "integrity": "sha512-umhPIcMrlBZ2aTWlWjUseW9LjQKxi1dpFlQS8DzsxB//5K+u6GLTC/JliPKHsd5kJVPIU6X/Hy0YvWOYPcMxBw==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@jest/types": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.0.tgz", + "integrity": "sha512-8pDeq/JVyAYw7jBGU83v8RMYAkdrRxLG3BGnAJuqaQAUd6GWBmND2uyl+awI88+hit48suLoLjNFtR+ZXxWaYg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@testing-library/dom": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.26.3.tgz", + "integrity": "sha512-/1P6taENE/H12TofJaS3L1J28HnXx8ZFhc338+XPR5y1E3g5ttOgu86DsGnV9/n2iPrfJQVUZ8eiGYZGSxculw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.10.3", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.1", + "lz-string": "^1.4.4", + "pretty-format": "^26.4.2" + } + }, + "@testing-library/react": { + "version": "10.4.9", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-10.4.9.tgz", + "integrity": "sha512-pHZKkqUy0tmiD81afs8xfiuseXfU/N7rAX3iKjeZYje86t9VaB0LrxYVa+OOsvkrveX5jCK3IjajVn2MbePvqA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.3", + "@testing-library/dom": "^7.22.3" + } + }, + "@types/aria-query": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz", + "integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==", + "dev": true + }, + "@types/bson": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", + "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/meteor": { + "version": "1.4.60", + "resolved": "https://registry.npmjs.org/@types/meteor/-/meteor-1.4.60.tgz", + "integrity": "sha512-NsuIIKtGABovJHrE2H0+PUDlGTuvCL3UjX9fgxJOk43oRzmA+1FMOnGz4n1n9J6G6vbw9PumdWZOWTZkH/NnRw==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/mongodb": "*", + "@types/react": "*", + "@types/underscore": "*" + } + }, + "@types/mongodb": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.30.tgz", + "integrity": "sha512-aKqOERMTA78LF5It0DeBRzFa4rXJ2Kmr+/EEG5GblSs0q1wRf3DqKErvQmFE8sFwsh5SBPuTU4h9yYHJY4dIJA==", + "dev": true, + "requires": { + "@types/bson": "*", + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.0.tgz", + "integrity": "sha512-BfbIHP9IapdupGhq/hc+jT5dyiBVZ2DdeC5WwJWQWDb0GijQlzUFAeIQn/2GtvZcd2HVUU7An8felIICFTC2qg==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, + "@types/react": { + "version": "16.9.53", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.53.tgz", + "integrity": "sha512-4nW60Sd4L7+WMXH1D6jCdVftuW7j4Za6zdp6tJ33Rqv0nk1ZAmQKML9ZLD4H0dehA3FZxXR/GM8gXplf82oNGw==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "@types/underscore": { + "version": "1.10.24", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.10.24.tgz", + "integrity": "sha512-T3NQD8hXNW2sRsSbLNjF/aBo18MyJlbw0lSpQHB/eZZtScPdexN4HSa8cByYwTw9Wy7KuOFr81mlDQcQQaZ79w==", + "dev": true + }, + "@types/yargs": { + "version": "15.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz", + "integrity": "sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "core-js-pure": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", + "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==", + "dev": true + }, + "csstype": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz", + "integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==", + "dev": true + }, + "dom-accessibility-api": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", + "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "pretty-format": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.0.tgz", + "integrity": "sha512-Uumr9URVB7bm6SbaByXtx+zGlS+0loDkFMHP0kHahMjmfCtmFY03iqd++5v3Ld6iB5TocVXlBN/T+DXMn9d4BA==", + "dev": true, + "requires": { + "@jest/types": "^26.6.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "react": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", + "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", + "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "react-test-renderer": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.13.1.tgz", + "integrity": "sha512-Sn2VRyOK2YJJldOqoh8Tn/lWQ+ZiKhyZTPtaO0Q6yNj+QDbmRkVFap6pZPy3YQk8DScRDfyqm/KxKYP9gCMRiQ==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "react-is": "^16.8.6", + "scheduler": "^0.19.1" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "typescript": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz", + "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==", + "dev": true + } + } +} diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js new file mode 100644 index 00000000..9367682f --- /dev/null +++ b/packages/react-meteor-accounts/package.js @@ -0,0 +1,17 @@ +/* global Package */ + +Package.describe({ + name: 'react-accounts', + summary: 'React hook for reactively tracking Meteor data', + version: '1.0.0', + documentation: 'README.md', + git: 'https://github.com/meteor/react-packages', +}); + +Package.onUse(function (api) { + api.versionsFrom('1.10'); + api.use('tracker'); + api.use('typescript'); + + api.mainModule('react-accounts.ts', ['client', 'server'], { lazy: true }); +}); diff --git a/packages/react-meteor-accounts/package.json b/packages/react-meteor-accounts/package.json new file mode 100644 index 00000000..03667b32 --- /dev/null +++ b/packages/react-meteor-accounts/package.json @@ -0,0 +1,15 @@ +{ + "name": "meteor-react-accounts", + "scripts": { + "make-types": "npx typescript *.tsx --jsx preserve --declaration --emitDeclarationOnly --outDir types" + }, + "devDependencies": { + "@testing-library/react": "^10.0.2", + "@types/meteor": "^1.4.42", + "@types/react": "^16.9.34", + "react": "16.13.1", + "react-dom": "16.13.1", + "react-test-renderer": "16.13.1", + "typescript": "^4.0.3" + } +} diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx new file mode 100644 index 00000000..95a92334 --- /dev/null +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -0,0 +1,43 @@ +import { Meteor } from 'meteor/meteor' +import { Tracker } from 'meteor/tracker' +import { useState, useEffect, forwardRef } from 'react' + +export const useUserId = () => { + const [userId, setUserId] = useState(Meteor.userId()) + useEffect(() => { + const computation = Tracker.autorun(() => { + setUserId(Meteor.userId()) + }) + return () => { + computation.stop() + } + }, []) + return userId +} + +export const withUserId = (Component) => ( + forwardRef((props, ref) => { + const userId = useUserId(); + return + }) +) + +export const useUser = () => { + const [user, setUser] = useState(Meteor.user()) + useEffect(() => { + const computation = Tracker.autorun(() => { + setUser(Meteor.user()) + }) + return () => { + computation.stop() + } + }, []) + return user +} + +export const withUser = (Component) => ( + forwardRef((props, ref) => { + const user = useUser(); + return + }) +) diff --git a/packages/react-meteor-accounts/types/react-accounts.d.ts b/packages/react-meteor-accounts/types/react-accounts.d.ts new file mode 100644 index 00000000..c66598b5 --- /dev/null +++ b/packages/react-meteor-accounts/types/react-accounts.d.ts @@ -0,0 +1,6 @@ +/// +import { Meteor } from 'meteor/meteor'; +export declare const useUserId: () => string; +export declare const withUserId: (Component: any) => import("react").ForwardRefExoticComponent>; +export declare const useUser: () => Meteor.User; +export declare const withUser: (Component: any) => import("react").ForwardRefExoticComponent>; From 52b4a04f54a03c2708a7cbb3face1ba91618f1bc Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 9 Oct 2021 14:42:23 +0200 Subject: [PATCH 02/36] Fix link to mainModule file & compatibility versionsFrom --- packages/react-meteor-accounts/package.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index 9367682f..d298b4ce 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -8,10 +8,10 @@ Package.describe({ git: 'https://github.com/meteor/react-packages', }); -Package.onUse(function (api) { - api.versionsFrom('1.10'); +Package.onUse((api) => { + api.versionsFrom(['1.10', '2.3']); api.use('tracker'); api.use('typescript'); - api.mainModule('react-accounts.ts', ['client', 'server'], { lazy: true }); + api.mainModule('react-accounts.tsx', ['client', 'server'], { lazy: true }); }); From d6e70f64db0c2c5dfe2c8caf5f274b58b1bce391 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Wed, 20 Oct 2021 17:29:31 +0200 Subject: [PATCH 03/36] Published react-accounts@1.0.0-beta.1 --- packages/react-meteor-accounts/.versions | 18 ++++++++++++++++++ packages/react-meteor-accounts/package.js | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/react-meteor-accounts/.versions diff --git a/packages/react-meteor-accounts/.versions b/packages/react-meteor-accounts/.versions new file mode 100644 index 00000000..785711d1 --- /dev/null +++ b/packages/react-meteor-accounts/.versions @@ -0,0 +1,18 @@ +babel-compiler@7.7.0 +babel-runtime@1.5.0 +dynamic-import@0.7.2 +ecmascript@0.15.3 +ecmascript-runtime@0.8.0 +ecmascript-runtime-client@0.12.1 +ecmascript-runtime-server@0.11.0 +fetch@0.1.1 +inter-process-messaging@0.1.1 +meteor@1.10.0 +modern-browsers@0.1.7 +modules@0.17.0 +modules-runtime@0.12.0 +promise@0.12.0 +react-accounts@1.0.0-beta.1 +react-fast-refresh@0.1.1 +tracker@1.2.0 +typescript@4.3.5 diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index d298b4ce..3fa1fb84 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -3,7 +3,7 @@ Package.describe({ name: 'react-accounts', summary: 'React hook for reactively tracking Meteor data', - version: '1.0.0', + version: '1.0.0-beta.1', documentation: 'README.md', git: 'https://github.com/meteor/react-packages', }); From e026994327e733007bada70fbc1d5988c40c8206 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Sun, 12 Dec 2021 23:59:00 -0500 Subject: [PATCH 04/36] chore(react-meteor-accounts): add changelog; readme info and api docs (#347) * chore(docs): add changelog * chore(readme): add general info and api docs * chore(react-meteor-accounts): add note for min React version * chore(docs): fix link * chore(docs): add missing word * chore(docs): improve wording and HOC examples * chore(docs): improve HOC examples * chore(docs): improve usage summary * chore(docs): add data source summaries, args tables, return desc --- packages/react-meteor-accounts/CHANGELOG.md | 14 ++ packages/react-meteor-accounts/README.md | 172 +++++++++++++++++++- 2 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 packages/react-meteor-accounts/CHANGELOG.md diff --git a/packages/react-meteor-accounts/CHANGELOG.md b/packages/react-meteor-accounts/CHANGELOG.md new file mode 100644 index 00000000..5a77c659 --- /dev/null +++ b/packages/react-meteor-accounts/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +Release versions follow [Semantic Versioning 2.0.0 guidelines](https://semver.org/). + +## v1.0.0-beta.1 + +2021-10-20 (date of last commit) + +### Features + +- `useUserId`: initial implementation. +- `useUser`: initial implementation. +- `withUserId`: initial implementation. +- `withUser`: initial implementation. diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md index fe22d5de..ff6eab3f 100644 --- a/packages/react-meteor-accounts/README.md +++ b/packages/react-meteor-accounts/README.md @@ -1,4 +1,170 @@ -meteor/react-accounts -===================== +# react-meteor-accounts -A couple of simple hooks for accessing Meteor Accounts state. +Simple hooks and higher-order components (HOCs) for getting reactive, stateful values of Meteor's Accounts data sources. + +## Table of Contents + +- [Installation](#installation) + - [Peer npm dependencies](#peer-npm-dependencies) + - [Changelog](#changelog) +- [Usage](#usage) + - [`useUser` / `withUser`](#useuser--withUser) + - [`useUserId` / `withUserId`](#useuserid--withUserId) + +## Installation + +Install the package from Atmosphere: + +```shell +meteor add react-meteor-accounts +``` + +### Peer npm dependencies + +Install React if you have not already: + +```shell +meteor npm install react +``` + +_Note:_ The minimum supported version of React is v16.8 ("the one with hooks"). + +### Changelog + +For recent changes, check the [changelog](./CHANGELOG.md). + +## Usage + +Utilities for each data source are available for the two ways of writing React components: hooks and higher-order components (HOCs). Hooks can only be used in functional components. HOCs can be used for both functional and class components, but are primarily for the latter. + +_Note:_ All HOCs forward refs. + +### useUser() / withUser(...) + +Get a stateful value of the current user record from [`Meteor.user`](https://docs.meteor.com/api/accounts.html#Meteor-user), a reactive data source. + +The hook, `useUser()`, returns a stateful value of the current user record. + +- Arguments: *none*. +- Returns: `object | null`. + +The HOC, `withUser(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the current user record, `user`. + +- Arguments: + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| Component | `any` | yes | A React component. | + +- Returns: `React.ForwardRefExoticComponent`. + +Examples: + +```tsx +import React from 'react'; +import { useUser, withUser } from 'meteor/react-meteor-accounts'; + +// Hook +function Foo() { + const user = useUser(); + + if (user === null) { + return

Log in

; + } + + return

Hello {user.username}

; +} + +// HOC +class Bar extends React.Component { + render() { + if (this.props.user === null) { + return

Log in

; + } + + return

Hello {this.props.user.username}

; + } +} + +const WrappedBar = withUser(Bar); +``` + +TypeScript signatures: + +```ts +// Hook +const useUser: () => Meteor.User; + +// HOC +const withUser: (Component: any) => React.ForwardRefExoticComponent>; +``` + +### useUserId() / withUserId(...) + +Get a stateful value of the current user id from [`Meteor.userId`](https://docs.meteor.com/api/accounts.html#Meteor-userId), a reactive data source. + +The hook, `useUserId()`, returns a stateful value of the current user id. + +- Arguments: *none*. +- Returns: `string`. + +The HOC, `withUserId(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the current user id, `userId`. + +- Arguments: + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| Component | `any` | yes | A React component. | + +- Returns: `React.ForwardRefExoticComponent`. + +Examples: + +```tsx +import React from 'react'; +import { useUserId, withUserId } from 'meteor/react-meteor-accounts'; + +// Hook +function Foo() { + const userId = useUserId(); + + return ( +
+

Account Details

+ {userId ? ( +

Your unique account id is {userId}.

+ ) : ( +

Log-in to view your account details.

+ )} +
+ ); +} + +// HOC +class Bar extends React.Component { + render() { + return ( +
+

Account Details

+ {this.props.userId ? ( +

Your unique account id is {this.props.userId}.

+ ) : ( +

Log-in to view your account details.

+ )} +
+ ); + } +} + +const WrappedBar = withUserId(Bar); +``` + +TypeScript signatures: + +```ts +// Hook +const useUserId: () => string; + +// HOC +const withUserId: (Component: any) => React.ForwardRefExoticComponent>; +``` From d51cfe30b16c0767182315db3925758d9347f27a Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 12:14:19 -0500 Subject: [PATCH 05/36] chore: improve package.js description --- packages/react-meteor-accounts/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index 3fa1fb84..4ecd2209 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -2,7 +2,7 @@ Package.describe({ name: 'react-accounts', - summary: 'React hook for reactively tracking Meteor data', + summary: 'React hook for reactively tracking Meteor Accounts data', version: '1.0.0-beta.1', documentation: 'README.md', git: 'https://github.com/meteor/react-packages', From c220e187e08bb17354b1b3605c890f5db22254e3 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 12:36:40 -0500 Subject: [PATCH 06/36] chore: add dep on 'accounts-base' --- packages/react-meteor-accounts/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index 4ecd2209..388fa7d0 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -10,8 +10,8 @@ Package.describe({ Package.onUse((api) => { api.versionsFrom(['1.10', '2.3']); - api.use('tracker'); - api.use('typescript'); + + api.use(['accounts-base', 'tracker', 'typescript']); api.mainModule('react-accounts.tsx', ['client', 'server'], { lazy: true }); }); From d399162a3a3c2675425881c67cb0471ca75c4722 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 12:37:39 -0500 Subject: [PATCH 07/36] fix(types): wrong / incomplete function signatures --- packages/react-meteor-accounts/package.json | 2 +- .../react-meteor-accounts/react-accounts.tsx | 18 +++++++++--------- .../types/react-accounts.d.ts | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/react-meteor-accounts/package.json b/packages/react-meteor-accounts/package.json index 03667b32..de1eac94 100644 --- a/packages/react-meteor-accounts/package.json +++ b/packages/react-meteor-accounts/package.json @@ -1,7 +1,7 @@ { "name": "meteor-react-accounts", "scripts": { - "make-types": "npx typescript *.tsx --jsx preserve --declaration --emitDeclarationOnly --outDir types" + "make-types": "npx typescript *.tsx --jsx preserve --declaration --emitDeclarationOnly --esModuleInterop --outDir types" }, "devDependencies": { "@testing-library/react": "^10.0.2", diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 95a92334..9753e8cc 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -1,8 +1,8 @@ import { Meteor } from 'meteor/meteor' import { Tracker } from 'meteor/tracker' -import { useState, useEffect, forwardRef } from 'react' +import React, { useState, useEffect, forwardRef } from 'react' -export const useUserId = () => { +export function useUserId(): string | null { const [userId, setUserId] = useState(Meteor.userId()) useEffect(() => { const computation = Tracker.autorun(() => { @@ -15,14 +15,14 @@ export const useUserId = () => { return userId } -export const withUserId = (Component) => ( - forwardRef((props, ref) => { +export function withUserId

(Component: React.ComponentType

) { + return forwardRef((props: P, ref) => { const userId = useUserId(); return }) -) +} -export const useUser = () => { +export function useUser(): Meteor.User | null { const [user, setUser] = useState(Meteor.user()) useEffect(() => { const computation = Tracker.autorun(() => { @@ -35,9 +35,9 @@ export const useUser = () => { return user } -export const withUser = (Component) => ( - forwardRef((props, ref) => { +export function withUser

(Component: React.ComponentType

) { + return forwardRef((props: P, ref) => { const user = useUser(); return }) -) +} diff --git a/packages/react-meteor-accounts/types/react-accounts.d.ts b/packages/react-meteor-accounts/types/react-accounts.d.ts index c66598b5..b813f3db 100644 --- a/packages/react-meteor-accounts/types/react-accounts.d.ts +++ b/packages/react-meteor-accounts/types/react-accounts.d.ts @@ -1,6 +1,6 @@ -/// import { Meteor } from 'meteor/meteor'; -export declare const useUserId: () => string; -export declare const withUserId: (Component: any) => import("react").ForwardRefExoticComponent>; -export declare const useUser: () => Meteor.User; -export declare const withUser: (Component: any) => import("react").ForwardRefExoticComponent>; +import React from 'react'; +export declare function useUserId(): string | null; +export declare function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; +export declare function useUser(): Meteor.User | null; +export declare function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; From 862394e0db6fc17c1e4369cd7bf39e5b825954c4 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 12:44:37 -0500 Subject: [PATCH 08/36] feat: add index file and check React version --- packages/react-meteor-accounts/index.ts | 12 ++++++++++++ packages/react-meteor-accounts/package.js | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 packages/react-meteor-accounts/index.ts diff --git a/packages/react-meteor-accounts/index.ts b/packages/react-meteor-accounts/index.ts new file mode 100644 index 00000000..074d0fd5 --- /dev/null +++ b/packages/react-meteor-accounts/index.ts @@ -0,0 +1,12 @@ +import { Meteor } from 'meteor/meteor'; +import React from 'react'; + +if (Meteor.isDevelopment) { + // Custom check instead of `checkNpmVersions` to reduce prod bundle size (~8kb). + const v = React.version.split('.').map(val => parseInt(val)); + if (v[0] < 16 || (v[0] === 16 && v[1] < 8)) { + console.warn('react-meteor-accounts requires React version >= 16.8.'); + } +} + +export { useUser, withUser, useUserId, withUserId } from './react-accounts'; diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index 388fa7d0..915997ef 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -13,5 +13,5 @@ Package.onUse((api) => { api.use(['accounts-base', 'tracker', 'typescript']); - api.mainModule('react-accounts.tsx', ['client', 'server'], { lazy: true }); + api.mainModule('index.ts', ['client', 'server'], { lazy: true }); }); From 033068555f742912905db10def49af821d7be469 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 13:19:16 -0500 Subject: [PATCH 09/36] chore: add jsdoc descriptions to fns --- .../react-meteor-accounts/react-accounts.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 9753e8cc..f5940ebb 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -2,6 +2,10 @@ import { Meteor } from 'meteor/meteor' import { Tracker } from 'meteor/tracker' import React, { useState, useEffect, forwardRef } from 'react' +/** + * Hook to get a stateful value of the current user id from `Meteor.userId`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-userId + */ export function useUserId(): string | null { const [userId, setUserId] = useState(Meteor.userId()) useEffect(() => { @@ -15,6 +19,10 @@ export function useUserId(): string | null { return userId } +/** + * HOC to forward a stateful value of the current user id from `Meteor.userId`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-userId + */ export function withUserId

(Component: React.ComponentType

) { return forwardRef((props: P, ref) => { const userId = useUserId(); @@ -22,6 +30,10 @@ export function withUserId

(Component: React.ComponentType

) { }) } +/** + * Hook to get a stateful value of the current user record from `Meteor.user`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-user + */ export function useUser(): Meteor.User | null { const [user, setUser] = useState(Meteor.user()) useEffect(() => { @@ -35,6 +47,10 @@ export function useUser(): Meteor.User | null { return user } +/** + * HOC to get a stateful value of the current user record from `Meteor.user`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-user + */ export function withUser

(Component: React.ComponentType

) { return forwardRef((props: P, ref) => { const user = useUser(); From 2c1730a034c947a312f5bfd069873cc02584bdfa Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 13:23:53 -0500 Subject: [PATCH 10/36] chore(docs): adjust return types and ts signatures --- packages/react-meteor-accounts/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md index ff6eab3f..1e1e1ca9 100644 --- a/packages/react-meteor-accounts/README.md +++ b/packages/react-meteor-accounts/README.md @@ -93,10 +93,10 @@ TypeScript signatures: ```ts // Hook -const useUser: () => Meteor.User; +function useUser(): Meteor.User | null; // HOC -const withUser: (Component: any) => React.ForwardRefExoticComponent>; +function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; ``` ### useUserId() / withUserId(...) @@ -106,7 +106,7 @@ Get a stateful value of the current user id from [`Meteor.userId`](https://docs. The hook, `useUserId()`, returns a stateful value of the current user id. - Arguments: *none*. -- Returns: `string`. +- Returns: `string | null`. The HOC, `withUserId(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the current user id, `userId`. @@ -114,7 +114,7 @@ The HOC, `withUserId(Component)`, returns a wrapped version of `Component`, wher | Argument | Type | Required | Description | | --- | --- | --- | --- | -| Component | `any` | yes | A React component. | +| Component | `React.ComponentType` | yes | A React component. | - Returns: `React.ForwardRefExoticComponent`. @@ -163,8 +163,8 @@ TypeScript signatures: ```ts // Hook -const useUserId: () => string; +function useUserId(): string | null; // HOC -const withUserId: (Component: any) => React.ForwardRefExoticComponent>; +function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; ``` From 8b45d7cac3f1e52990129cfda276f75cca19bbd7 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 13:31:45 -0500 Subject: [PATCH 11/36] feat: let forwarded props be overridable --- packages/react-meteor-accounts/react-accounts.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index f5940ebb..886460b1 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -26,7 +26,7 @@ export function useUserId(): string | null { export function withUserId

(Component: React.ComponentType

) { return forwardRef((props: P, ref) => { const userId = useUserId(); - return + return }) } @@ -54,6 +54,6 @@ export function useUser(): Meteor.User | null { export function withUser

(Component: React.ComponentType

) { return forwardRef((props: P, ref) => { const user = useUser(); - return + return }) } From aa2bec4e316740baed670c13747d91c94bce06f8 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 13:36:27 -0500 Subject: [PATCH 12/36] fix: hoc type signatures not injecting prop --- packages/react-meteor-accounts/react-accounts.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 886460b1..1dc1da3e 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -23,7 +23,9 @@ export function useUserId(): string | null { * HOC to forward a stateful value of the current user id from `Meteor.userId`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-userId */ -export function withUserId

(Component: React.ComponentType

) { +export function withUserId

(Component: React.ComponentType

) { return forwardRef((props: P, ref) => { const userId = useUserId(); return @@ -51,7 +53,9 @@ export function useUser(): Meteor.User | null { * HOC to get a stateful value of the current user record from `Meteor.user`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-user */ -export function withUser

(Component: React.ComponentType

) { +export function withUser

(Component: React.ComponentType

) { return forwardRef((props: P, ref) => { const user = useUser(); return From ee430cf284123c60b73f9bca8bda0d62d305c682 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 13:57:04 -0500 Subject: [PATCH 13/36] feat: add utils for loggingIn and loggingOut --- .../react-meteor-accounts/react-accounts.tsx | 73 ++++++++++++++++++- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 1dc1da3e..9c4add63 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -2,8 +2,15 @@ import { Meteor } from 'meteor/meteor' import { Tracker } from 'meteor/tracker' import React, { useState, useEffect, forwardRef } from 'react' +// Augmentation to add missing signature +declare module 'meteor/meteor' { + module Meteor { + function loggingOut(): boolean; + } +} + /** - * Hook to get a stateful value of the current user id from `Meteor.userId`, a reactive data source. + * Hook to get a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-userId */ export function useUserId(): string | null { @@ -20,7 +27,7 @@ export function useUserId(): string | null { } /** - * HOC to forward a stateful value of the current user id from `Meteor.userId`, a reactive data source. + * HOC to forward a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-userId */ export function withUserId

}) } + +/** + * Hook to get a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses `Meteor.loggingIn`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingIn + */ +export function useLoggingIn(): boolean { + const [loggingIn, setLoggingIn] = useState(Meteor.loggingIn()) + useEffect(() => { + const computation = Tracker.autorun(() => { + setLoggingIn(Meteor.loggingIn()) + }) + return () => { + computation.stop() + } + }, []) + return loggingIn +} + +/** + * HOC to forward a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses `Meteor.loggingIn`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingIn + */ +export function withLoggingIn

(Component: React.ComponentType

) { + return forwardRef((props: P, ref) => { + const loggingIn = useLoggingIn(); + return + }) +} + +/** + * Hook to get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + */ +export function useLoggingOut(): boolean { + const [loggingOut, setLoggingOut] = useState(Meteor.loggingOut()) + useEffect(() => { + const computation = Tracker.autorun(() => { + setLoggingOut(Meteor.loggingOut()) + }) + return () => { + computation.stop() + } + }, []) + return loggingOut +} + +/** + * HOC to forward a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + */ +export function withLoggingOut

(Component: React.ComponentType

) { + return forwardRef((props: P, ref) => { + const loggingOut = useLoggingOut(); + return + }) +} From 211fce11aa2111da7fd82b1b85977faa327bbf5f Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 15:42:34 -0500 Subject: [PATCH 14/36] test(useUserId): initial tests --- packages/react-meteor-accounts/index.tests.ts | 1 + .../react-meteor-accounts/package-lock.json | 62 +++++++++ packages/react-meteor-accounts/package.js | 13 ++ packages/react-meteor-accounts/package.json | 1 + .../react-accounts.tests.tsx | 122 ++++++++++++++++++ 5 files changed, 199 insertions(+) create mode 100644 packages/react-meteor-accounts/index.tests.ts create mode 100644 packages/react-meteor-accounts/react-accounts.tests.tsx diff --git a/packages/react-meteor-accounts/index.tests.ts b/packages/react-meteor-accounts/index.tests.ts new file mode 100644 index 00000000..628be844 --- /dev/null +++ b/packages/react-meteor-accounts/index.tests.ts @@ -0,0 +1 @@ +import './react-accounts.tests.tsx'; diff --git a/packages/react-meteor-accounts/package-lock.json b/packages/react-meteor-accounts/package-lock.json index b4ae92e5..abdc6559 100644 --- a/packages/react-meteor-accounts/package-lock.json +++ b/packages/react-meteor-accounts/package-lock.json @@ -100,6 +100,30 @@ "@testing-library/dom": "^7.22.3" } }, + "@testing-library/react-hooks": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-7.0.2.tgz", + "integrity": "sha512-dYxpz8u9m4q1TuzfcUApqi8iFfR6R0FaMbr2hjZJy1uC8z+bO/K4v8Gs9eogGKYQop7QsrBTFkv/BCF7MzD2Cg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@types/react": ">=16.9.0", + "@types/react-dom": ">=16.9.0", + "@types/react-test-renderer": ">=16.9.0", + "react-error-boundary": "^3.1.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "@types/aria-query": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz", @@ -192,6 +216,24 @@ "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", + "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-test-renderer": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz", + "integrity": "sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/underscore": { "version": "1.10.24", "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.10.24.tgz", @@ -433,6 +475,26 @@ "scheduler": "^0.19.1" } }, + "react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index 915997ef..ec90f6be 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -15,3 +15,16 @@ Package.onUse((api) => { api.mainModule('index.ts', ['client', 'server'], { lazy: true }); }); + +Package.onTest((api) => { + api.use([ + 'accounts-base', + 'accounts-password', + 'react-accounts', + 'tinytest', + 'tracker', + 'typescript', + ]); + + api.mainModule('index.tests.ts'); +}); diff --git a/packages/react-meteor-accounts/package.json b/packages/react-meteor-accounts/package.json index de1eac94..8dc3e3e6 100644 --- a/packages/react-meteor-accounts/package.json +++ b/packages/react-meteor-accounts/package.json @@ -5,6 +5,7 @@ }, "devDependencies": { "@testing-library/react": "^10.0.2", + "@testing-library/react-hooks": "^7.0.2", "@types/meteor": "^1.4.42", "@types/react": "^16.9.34", "react": "16.13.1", diff --git a/packages/react-meteor-accounts/react-accounts.tests.tsx b/packages/react-meteor-accounts/react-accounts.tests.tsx new file mode 100644 index 00000000..6b77545a --- /dev/null +++ b/packages/react-meteor-accounts/react-accounts.tests.tsx @@ -0,0 +1,122 @@ +import { renderHook } from '@testing-library/react-hooks/dom'; +import { Accounts } from 'meteor/accounts-base'; +import { Meteor } from 'meteor/meteor'; +import { Tinytest } from 'meteor/tinytest'; +import { useLoggingIn, useLoggingOut, useUser, useUserId } from './react-accounts'; + +// Prepare method for clearing DB (doesn't need to be isomorphic). +if (Meteor.isServer) { + Meteor.methods({ + reset() { + const res = Meteor.users.remove({}); + console.log(`method - reset - ${res}`) + return res + }, + }); +} + +if (Meteor.isClient) { + // fixture data + const username = 'username'; + const password = 'password'; + + // common test actions + async function login() { + console.log('before login'); + await new Promise((resolve, reject) => { + Meteor.loginWithPassword(username, password, (error) => { + if (error) reject(error); + else resolve(); + }) + }) + console.log('after login'); + } + async function logout() { + console.log('before logout'); + await new Promise((resolve, reject) => { + Meteor.logout((error) => { + if (error) reject(error); + else resolve(); + }) + }) + console.log('after logout'); + } + + // common test arrangements + async function beforeEach() { + console.log('before beforeEach'); + console.log('beforeEach - before call reset'); + // reset DB; must complete before creation to avoid potential overlap + await new Promise((resolve, reject) => { + Meteor.call('reset', (error, result) => { + console.log(`call - reset - ${result} - ${error}`) + if (error) reject(error); + else resolve(result); + }) + }); + console.log('beforeEach - after call reset'); + // prepare sample user + console.log('beforeEach - before createUser'); + await new Promise((resolve, reject) => { + Accounts.createUser({ username, password }, (error) => { + if (error) reject(error); + else resolve(); + }) + }); + console.log('beforeEach -before createUser'); + // logout since `createUser` auto-logs-in + await logout(); + console.log('after beforeEach'); + } + async function afterEach() { + console.log('before afterEach'); + await logout(); + console.log('after afterEach'); + } + + + // NOTE: each test body has three blocks: Arrange, Act, Assert. + + Tinytest.addAsync('useUserId - has initial value of `null`', async function (test, onComplete) { + console.log('test - before - beforeEach'); + try { + await beforeEach(); + } catch (error) { + console.log('test - catch - beforeEach') + console.error(error) + throw error; + } + console.log('test - after - beforeEach'); + + const { result } = renderHook(() => useUserId()); + + test.isNull(result.current, 'Expect initial value to be `null`'); + onComplete(); + }); + + Tinytest.addAsync('useUserId - is reactive to login', async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useUserId()); + // use `waitFor*` instead of `await`; mimics consumer usage + login(); + await waitForNextUpdate(); + + test.isNotNull(result.current, 'Expect value after login to be not `null`') + onComplete(); + }); + + + Tinytest.addAsync('useUserId - is reactive to logout', async function (test, onComplete) { + await beforeEach(); + await login(); + + const { result, waitForNextUpdate } = renderHook(() => useUserId()); + // use `waitFor*` instead of `await`; mimics consumer usage + logout(); + await waitForNextUpdate(); + + test.isNull(result.current, 'Expect value after logout to be `null`') + onComplete(); + }); +} From e39a4cb2e02194488410655b8115eaf32339fb45 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 15:53:19 -0500 Subject: [PATCH 15/36] test(useLoggingIn): add initial tests --- .../react-accounts.tests.tsx | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tests.tsx b/packages/react-meteor-accounts/react-accounts.tests.tsx index 6b77545a..685d069e 100644 --- a/packages/react-meteor-accounts/react-accounts.tests.tsx +++ b/packages/react-meteor-accounts/react-accounts.tests.tsx @@ -22,75 +22,50 @@ if (Meteor.isClient) { // common test actions async function login() { - console.log('before login'); await new Promise((resolve, reject) => { - Meteor.loginWithPassword(username, password, (error) => { - if (error) reject(error); - else resolve(); - }) + Meteor.loginWithPassword(username, password, (error) => { + if (error) reject(error); + else resolve(); }) - console.log('after login'); + }) } async function logout() { - console.log('before logout'); await new Promise((resolve, reject) => { Meteor.logout((error) => { if (error) reject(error); else resolve(); }) }) - console.log('after logout'); } // common test arrangements async function beforeEach() { - console.log('before beforeEach'); - console.log('beforeEach - before call reset'); // reset DB; must complete before creation to avoid potential overlap await new Promise((resolve, reject) => { Meteor.call('reset', (error, result) => { - console.log(`call - reset - ${result} - ${error}`) if (error) reject(error); else resolve(result); }) }); - console.log('beforeEach - after call reset'); // prepare sample user - console.log('beforeEach - before createUser'); await new Promise((resolve, reject) => { Accounts.createUser({ username, password }, (error) => { if (error) reject(error); else resolve(); }) }); - console.log('beforeEach -before createUser'); // logout since `createUser` auto-logs-in await logout(); - console.log('after beforeEach'); - } - async function afterEach() { - console.log('before afterEach'); - await logout(); - console.log('after afterEach'); } - // NOTE: each test body has three blocks: Arrange, Act, Assert. Tinytest.addAsync('useUserId - has initial value of `null`', async function (test, onComplete) { - console.log('test - before - beforeEach'); - try { - await beforeEach(); - } catch (error) { - console.log('test - catch - beforeEach') - console.error(error) - throw error; - } - console.log('test - after - beforeEach'); + await beforeEach(); const { result } = renderHook(() => useUserId()); - test.isNull(result.current, 'Expect initial value to be `null`'); + test.isNull(result.current); onComplete(); }); @@ -102,11 +77,10 @@ if (Meteor.isClient) { login(); await waitForNextUpdate(); - test.isNotNull(result.current, 'Expect value after login to be not `null`') + test.isNotNull(result.current) onComplete(); }); - Tinytest.addAsync('useUserId - is reactive to logout', async function (test, onComplete) { await beforeEach(); await login(); @@ -116,7 +90,41 @@ if (Meteor.isClient) { logout(); await waitForNextUpdate(); - test.isNull(result.current, 'Expect value after logout to be `null`') + test.isNull(result.current) + onComplete(); + }); + + Tinytest.addAsync('useLoggingIn - has initial value of `false`', async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useLoggingIn()); + + test.isFalse(result.current); + onComplete(); + }); + + Tinytest.addAsync('useLoggingIn - is reactive to login starting', async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingIn()); + login(); + // first update will be while login strategy is in progress + await waitForNextUpdate(); + + test.isTrue(result.current); + onComplete(); + }); + + Tinytest.addAsync('useLoggingIn - is reactive to login finishing', async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingIn()); + login(); + await waitForNextUpdate(); + // second update will be after login strategy finishes + await waitForNextUpdate(); + + test.isFalse(result.current); onComplete(); }); } From 33f64e774a985314c7363cff90a0eea739308b17 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 15:53:34 -0500 Subject: [PATCH 16/36] test(useLoggingOut): add initial tests --- .../react-accounts.tests.tsx | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/react-meteor-accounts/react-accounts.tests.tsx b/packages/react-meteor-accounts/react-accounts.tests.tsx index 685d069e..8e245aeb 100644 --- a/packages/react-meteor-accounts/react-accounts.tests.tsx +++ b/packages/react-meteor-accounts/react-accounts.tests.tsx @@ -127,4 +127,38 @@ if (Meteor.isClient) { test.isFalse(result.current); onComplete(); }); + + Tinytest.addAsync('useLoggingOut - has initial value of `false`', async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useLoggingOut()); + + test.isFalse(result.current); + onComplete(); + }); + + Tinytest.addAsync('useLoggingOut - is reactive to logout starting', async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingOut()); + logout(); + // first update will be while logout is in progress + await waitForNextUpdate(); + + test.isTrue(result.current); + onComplete(); + }); + + Tinytest.addAsync('useLoggingOut - is reactive to logout finishing', async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingOut()); + logout(); + await waitForNextUpdate(); + // second update will be after logout finishes + await waitForNextUpdate(); + + test.isFalse(result.current); + onComplete(); + }); } From 4129cbff705bc2604faa9f170444c7c6369d8d9f Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 16:53:41 -0500 Subject: [PATCH 17/36] test(useUser): add initial tests - adjust internal of useUser to fix returning `undefined` after logout (not in signature) --- .../react-accounts.tests.tsx | 39 +++++++++++++++++-- .../react-meteor-accounts/react-accounts.tsx | 7 +++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tests.tsx b/packages/react-meteor-accounts/react-accounts.tests.tsx index 8e245aeb..32c320a5 100644 --- a/packages/react-meteor-accounts/react-accounts.tests.tsx +++ b/packages/react-meteor-accounts/react-accounts.tests.tsx @@ -8,9 +8,7 @@ import { useLoggingIn, useLoggingOut, useUser, useUserId } from './react-account if (Meteor.isServer) { Meteor.methods({ reset() { - const res = Meteor.users.remove({}); - console.log(`method - reset - ${res}`) - return res + Meteor.users.remove({}); }, }); } @@ -161,4 +159,39 @@ if (Meteor.isClient) { test.isFalse(result.current); onComplete(); }); + + Tinytest.addAsync('useUser - has initial value of `null`', async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useUser()); + + test.isNull(result.current); + onComplete(); + }); + + Tinytest.addAsync('useUser - is reactive to login', async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useUser()); + // use `waitFor*` instead of `await`; mimics consumer usage + login(); + await waitForNextUpdate(); + + test.isNotNull(result.current) + test.equal(result.current.username, username, 'Expected username to match') + onComplete(); + }); + + Tinytest.addAsync('useUser - is reactive to logout', async function (test, onComplete) { + await beforeEach(); + await login(); + + const { result, waitForNextUpdate } = renderHook(() => useUser()); + // use `waitFor*` instead of `await`; mimics consumer usage + logout(); + await waitForNextUpdate(); + + test.isNull(result.current) + onComplete(); + }); } diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 9c4add63..30795f1e 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -47,7 +47,12 @@ export function useUser(): Meteor.User | null { const [user, setUser] = useState(Meteor.user()) useEffect(() => { const computation = Tracker.autorun(() => { - setUser(Meteor.user()) + let user = Meteor.user(); + // `Meteor.user` returns `undefined` after logout, but that ruins type signature and test parity. So, cast until that's fixed. + if (user === undefined) { + user = null; + } + setUser(user) }) return () => { computation.stop() From c51455db4621e8f6852350d7d7aef9839e3baa1b Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 18:53:36 -0500 Subject: [PATCH 18/36] fix(types): HOC's requiring their inserted prop on wrapper instantiation --- .../react-meteor-accounts/react-accounts.tsx | 136 +++++++++++------- 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 30795f1e..020806d2 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -26,25 +26,37 @@ export function useUserId(): string | null { return userId } +export interface WithUserIdProps { + userId: string | null; +} + /** * HOC to forward a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-userId */ -export function withUserId

(Component: React.ComponentType

) { - return forwardRef((props: P, ref) => { - const userId = useUserId(); - return - }) +export function withUserId

(Component: React.ComponentType

) { + return forwardRef( + // Use `Omit` so instantiation doesn't require the prop. Union with `Partial` because prop should be optionally overridable / the wrapped component will be prepared for it anyways. + (props: Omit & Partial, ref) => { + const userId = useUserId(); + return ( + + ); + } + ); } /** * Hook to get a stateful value of the current user record. Uses `Meteor.user`, a reactive data source. - * @see https://docs.meteor.com/api/accounts.html#Meteor-user + * @see https://docs.meteor.com/api/accounts.html#Meteor-user */ export function useUser(): Meteor.User | null { - const [user, setUser] = useState(Meteor.user()) + const [user, setUser] = useState(Meteor.user()); useEffect(() => { const computation = Tracker.autorun(() => { let user = Meteor.user(); @@ -52,26 +64,30 @@ export function useUser(): Meteor.User | null { if (user === undefined) { user = null; } - setUser(user) - }) + setUser(user); + }); return () => { - computation.stop() - } - }, []) - return user + computation.stop(); + }; + }, []); + return user; +} + +export interface WithUserProps { + user: Meteor.User | null; } /** * HOC to get a stateful value of the current user record. Uses `Meteor.user`, a reactive data source. - * @see https://docs.meteor.com/api/accounts.html#Meteor-user + * @see https://docs.meteor.com/api/accounts.html#Meteor-user */ -export function withUser

(Component: React.ComponentType

) { - return forwardRef((props: P, ref) => { - const user = useUser(); - return - }) +export function withUser

(Component: React.ComponentType

) { + return forwardRef( + (props: Omit & Partial, ref) => { + const user = useUser(); + return ; + } + ); } /** @@ -79,55 +95,73 @@ export function withUser

{ const computation = Tracker.autorun(() => { - setLoggingIn(Meteor.loggingIn()) - }) + setLoggingIn(Meteor.loggingIn()); + }); return () => { - computation.stop() - } - }, []) - return loggingIn + computation.stop(); + }; + }, []); + return loggingIn; +} + +export interface WithLoggingInProps { + loggingIn: boolean; } /** * HOC to forward a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses `Meteor.loggingIn`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingIn */ -export function withLoggingIn

(Component: React.ComponentType

) { - return forwardRef((props: P, ref) => { - const loggingIn = useLoggingIn(); - return - }) +export function withLoggingIn

(Component: React.ComponentType

) { + return forwardRef( + ( + props: Omit & Partial, + ref + ) => { + const loggingIn = useLoggingIn(); + return ( + + ); + } + ); } /** * Hook to get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. */ export function useLoggingOut(): boolean { - const [loggingOut, setLoggingOut] = useState(Meteor.loggingOut()) + const [loggingOut, setLoggingOut] = useState(Meteor.loggingOut()); useEffect(() => { const computation = Tracker.autorun(() => { - setLoggingOut(Meteor.loggingOut()) - }) + setLoggingOut(Meteor.loggingOut()); + }); return () => { - computation.stop() - } - }, []) - return loggingOut + computation.stop(); + }; + }, []); + return loggingOut; +} + +export interface WithLoggingOutProps { + loggingOut: boolean; } /** * HOC to forward a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. */ -export function withLoggingOut

(Component: React.ComponentType

) { - return forwardRef((props: P, ref) => { - const loggingOut = useLoggingOut(); - return - }) +export function withLoggingOut

(Component: React.ComponentType

) { + return forwardRef( + ( + props: Omit & Partial, + ref + ) => { + const loggingOut = useLoggingOut(); + return ( + + ); + } + ); } From 280bc7cd581ccdc94761b5a9c9fdb609363cb68a Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 18:53:45 -0500 Subject: [PATCH 19/36] test: add initial tests for HOCs --- .../react-accounts.tests.tsx | 437 ++++++++++++------ 1 file changed, 286 insertions(+), 151 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tests.tsx b/packages/react-meteor-accounts/react-accounts.tests.tsx index 32c320a5..834c8798 100644 --- a/packages/react-meteor-accounts/react-accounts.tests.tsx +++ b/packages/react-meteor-accounts/react-accounts.tests.tsx @@ -1,8 +1,23 @@ import { renderHook } from '@testing-library/react-hooks/dom'; -import { Accounts } from 'meteor/accounts-base'; -import { Meteor } from 'meteor/meteor'; -import { Tinytest } from 'meteor/tinytest'; -import { useLoggingIn, useLoggingOut, useUser, useUserId } from './react-accounts'; +import { cleanup, render, waitFor } from "@testing-library/react"; +import { Accounts } from "meteor/accounts-base"; +import { Meteor } from "meteor/meteor"; +import { Tinytest } from "meteor/tinytest"; +import React from "react"; +import { + useLoggingIn, + useLoggingOut, + useUser, + useUserId, + withLoggingIn, + WithLoggingInProps, + withLoggingOut, + WithLoggingOutProps, + withUser, + withUserId, + WithUserIdProps, + WithUserProps, +} from "./react-accounts"; // Prepare method for clearing DB (doesn't need to be isomorphic). if (Meteor.isServer) { @@ -15,42 +30,42 @@ if (Meteor.isServer) { if (Meteor.isClient) { // fixture data - const username = 'username'; - const password = 'password'; - + const username = "username"; + const password = "password"; + // common test actions async function login() { await new Promise((resolve, reject) => { Meteor.loginWithPassword(username, password, (error) => { if (error) reject(error); else resolve(); - }) - }) + }); + }); } async function logout() { await new Promise((resolve, reject) => { Meteor.logout((error) => { if (error) reject(error); else resolve(); - }) - }) + }); + }); } - + // common test arrangements async function beforeEach() { // reset DB; must complete before creation to avoid potential overlap await new Promise((resolve, reject) => { - Meteor.call('reset', (error, result) => { + Meteor.call("reset", (error, result) => { if (error) reject(error); else resolve(result); - }) + }); }); // prepare sample user await new Promise((resolve, reject) => { Accounts.createUser({ username, password }, (error) => { if (error) reject(error); else resolve(); - }) + }); }); // logout since `createUser` auto-logs-in await logout(); @@ -58,140 +73,260 @@ if (Meteor.isClient) { // NOTE: each test body has three blocks: Arrange, Act, Assert. - Tinytest.addAsync('useUserId - has initial value of `null`', async function (test, onComplete) { - await beforeEach(); - - const { result } = renderHook(() => useUserId()); - - test.isNull(result.current); - onComplete(); - }); - - Tinytest.addAsync('useUserId - is reactive to login', async function (test, onComplete) { - await beforeEach(); - - const { result, waitForNextUpdate } = renderHook(() => useUserId()); - // use `waitFor*` instead of `await`; mimics consumer usage - login(); - await waitForNextUpdate(); - - test.isNotNull(result.current) - onComplete(); - }); - - Tinytest.addAsync('useUserId - is reactive to logout', async function (test, onComplete) { - await beforeEach(); - await login(); - - const { result, waitForNextUpdate } = renderHook(() => useUserId()); - // use `waitFor*` instead of `await`; mimics consumer usage - logout(); - await waitForNextUpdate(); - - test.isNull(result.current) - onComplete(); - }); - - Tinytest.addAsync('useLoggingIn - has initial value of `false`', async function (test, onComplete) { - await beforeEach(); - - const { result } = renderHook(() => useLoggingIn()); - - test.isFalse(result.current); - onComplete(); - }); - - Tinytest.addAsync('useLoggingIn - is reactive to login starting', async function (test, onComplete) { - await beforeEach(); - - const { result, waitForNextUpdate } = renderHook(() => useLoggingIn()); - login(); - // first update will be while login strategy is in progress - await waitForNextUpdate(); - - test.isTrue(result.current); - onComplete(); - }); - - Tinytest.addAsync('useLoggingIn - is reactive to login finishing', async function (test, onComplete) { - await beforeEach(); - - const { result, waitForNextUpdate } = renderHook(() => useLoggingIn()); - login(); - await waitForNextUpdate(); - // second update will be after login strategy finishes - await waitForNextUpdate(); - - test.isFalse(result.current); - onComplete(); - }); - - Tinytest.addAsync('useLoggingOut - has initial value of `false`', async function (test, onComplete) { - await beforeEach(); - - const { result } = renderHook(() => useLoggingOut()); - - test.isFalse(result.current); - onComplete(); - }); - - Tinytest.addAsync('useLoggingOut - is reactive to logout starting', async function (test, onComplete) { - await beforeEach(); - - const { result, waitForNextUpdate } = renderHook(() => useLoggingOut()); - logout(); - // first update will be while logout is in progress - await waitForNextUpdate(); - - test.isTrue(result.current); - onComplete(); - }); - - Tinytest.addAsync('useLoggingOut - is reactive to logout finishing', async function (test, onComplete) { - await beforeEach(); - - const { result, waitForNextUpdate } = renderHook(() => useLoggingOut()); - logout(); - await waitForNextUpdate(); - // second update will be after logout finishes - await waitForNextUpdate(); - - test.isFalse(result.current); - onComplete(); - }); - - Tinytest.addAsync('useUser - has initial value of `null`', async function (test, onComplete) { - await beforeEach(); - - const { result } = renderHook(() => useUser()); - - test.isNull(result.current); - onComplete(); - }); - - Tinytest.addAsync('useUser - is reactive to login', async function (test, onComplete) { - await beforeEach(); - - const { result, waitForNextUpdate } = renderHook(() => useUser()); - // use `waitFor*` instead of `await`; mimics consumer usage - login(); - await waitForNextUpdate(); - - test.isNotNull(result.current) - test.equal(result.current.username, username, 'Expected username to match') - onComplete(); - }); - - Tinytest.addAsync('useUser - is reactive to logout', async function (test, onComplete) { - await beforeEach(); - await login(); - - const { result, waitForNextUpdate } = renderHook(() => useUser()); - // use `waitFor*` instead of `await`; mimics consumer usage - logout(); - await waitForNextUpdate(); - - test.isNull(result.current) - onComplete(); - }); + Tinytest.addAsync( + "Hooks - useUserId - has initial value of `null`", + async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useUserId()); + + test.isNull(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useUserId - is reactive to login", + async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useUserId()); + // use `waitFor*` instead of `await`; mimics consumer usage + login(); + await waitForNextUpdate(); + + test.isNotNull(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useUserId - is reactive to logout", + async function (test, onComplete) { + await beforeEach(); + await login(); + + const { result, waitForNextUpdate } = renderHook(() => useUserId()); + // use `waitFor*` instead of `await`; mimics consumer usage + logout(); + await waitForNextUpdate(); + + test.isNull(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useLoggingIn - has initial value of `false`", + async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useLoggingIn()); + + test.isFalse(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useLoggingIn - is reactive to login starting", + async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingIn()); + login(); + // first update will be while login strategy is in progress + await waitForNextUpdate(); + + test.isTrue(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useLoggingIn - is reactive to login finishing", + async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingIn()); + login(); + await waitForNextUpdate(); + // second update will be after login strategy finishes + await waitForNextUpdate(); + + test.isFalse(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useLoggingOut - has initial value of `false`", + async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useLoggingOut()); + + test.isFalse(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useLoggingOut - is reactive to logout starting", + async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingOut()); + logout(); + // first update will be while logout is in progress + await waitForNextUpdate(); + + test.isTrue(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useLoggingOut - is reactive to logout finishing", + async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useLoggingOut()); + logout(); + await waitForNextUpdate(); + // second update will be after logout finishes + await waitForNextUpdate(); + + test.isFalse(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useUser - has initial value of `null`", + async function (test, onComplete) { + await beforeEach(); + + const { result } = renderHook(() => useUser()); + + test.isNull(result.current); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useUser - is reactive to login", + async function (test, onComplete) { + await beforeEach(); + + const { result, waitForNextUpdate } = renderHook(() => useUser()); + // use `waitFor*` instead of `await`; mimics consumer usage + login(); + await waitForNextUpdate(); + + test.isNotNull(result.current); + test.equal( + result.current.username, + username, + "Expected username to match" + ); + onComplete(); + } + ); + + Tinytest.addAsync( + "Hooks - useUser - is reactive to logout", + async function (test, onComplete) { + await beforeEach(); + await login(); + + const { result, waitForNextUpdate } = renderHook(() => useUser()); + // use `waitFor*` instead of `await`; mimics consumer usage + logout(); + await waitForNextUpdate(); + + test.isNull(result.current); + onComplete(); + } + ); + + // Since the HOCs wrap with hooks, the logic is already tested in 'Hooks' tests, and we only really need to test for prop forwarding. However, doing so for the "non-initial" case of all these values seems more prudent than just checking the default of `null` or `false`. + + // :NOTE: these tests can be flaky (like 1 in 5 runs). + + Tinytest.addAsync( + "HOCs - withUserId - forwards reactive value", + async function (test, onComplete) { + await beforeEach(); + function Foo({ userId }: WithUserIdProps) { + // need something we can easily find; we don't know the id + return {Boolean(userId).toString()}; + } + const FooWithUserId = withUserId(Foo); + const { findByText } = render(); + + login(); + + await waitFor(() => findByText("true")); + cleanup(); + onComplete(); + } + ); + + // :TODO: this is flaky, fails ~1 in 10 + Tinytest.addAsync( + "HOCs - withUser - forwards reactive value", + async function (test, onComplete) { + await beforeEach(); + function Foo({ user }: WithUserProps) { + return {user?.username || String(user)}; + } + const FooWithUser = withUser(Foo); + const { findByText } = render(); + + login(); + + await waitFor(() => findByText(username)); + cleanup(); + onComplete(); + } + ); + + Tinytest.addAsync( + "HOCs - withLoggingIn - forwards reactive value", + async function (test, onComplete) { + await beforeEach(); + function Foo({ loggingIn }: WithLoggingInProps) { + return {loggingIn.toString()}; + } + const FooWithLoggingIn = withLoggingIn(Foo); + const { findByText } = render(); + + login(); + + await waitFor(() => findByText("true")); + cleanup(); + onComplete(); + } + ); + + // :TODO: this is flaky, fails ~1 in 5 + Tinytest.addAsync( + "HOCs - withLoggingOut - forwards reactive value", + async function (test, onComplete) { + await beforeEach(); + function Foo({ loggingOut }: WithLoggingOutProps) { + return {loggingOut.toString()}; + } + const FooWithLoggingOut = withLoggingOut(Foo); + const { findByText } = render(); + await login(); + + logout(); + + await waitFor(() => findByText("true")); + cleanup(); + onComplete(); + } + ); } From bafab1b998c3e2f1b9fe853e651ae6beb500854f Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 19:24:09 -0500 Subject: [PATCH 20/36] chore(docs): add sections for hooks/HOCs of loggingIn/Out --- packages/react-meteor-accounts/README.md | 136 +++++++++++++++++- packages/react-meteor-accounts/package.js | 1 - .../types/react-accounts.d.ts | 55 ++++++- 3 files changed, 185 insertions(+), 7 deletions(-) diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md index 1e1e1ca9..d5c30154 100644 --- a/packages/react-meteor-accounts/README.md +++ b/packages/react-meteor-accounts/README.md @@ -41,7 +41,7 @@ _Note:_ All HOCs forward refs. ### useUser() / withUser(...) -Get a stateful value of the current user record from [`Meteor.user`](https://docs.meteor.com/api/accounts.html#Meteor-user), a reactive data source. +Get a stateful value of the current user record. Uses [`Meteor.user`](https://docs.meteor.com/api/accounts.html#Meteor-user), a reactive data source. The hook, `useUser()`, returns a stateful value of the current user record. @@ -96,12 +96,12 @@ TypeScript signatures: function useUser(): Meteor.User | null; // HOC -function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; +function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; ``` ### useUserId() / withUserId(...) -Get a stateful value of the current user id from [`Meteor.userId`](https://docs.meteor.com/api/accounts.html#Meteor-userId), a reactive data source. +Get a stateful value of the current user id. Uses [`Meteor.userId`](https://docs.meteor.com/api/accounts.html#Meteor-userId), a reactive data source. The hook, `useUserId()`, returns a stateful value of the current user id. @@ -166,5 +166,133 @@ TypeScript signatures: function useUserId(): string | null; // HOC -function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; +function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +``` + +### useLoggingIn() / withLoggingIn(...) + +Get a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses [`Meteor.loggingIn`](https://docs.meteor.com/api/accounts.html#Meteor-loggingIn), a reactive data source. + +The hook, `useLoggingIn()`, returns the stateful value. + +- Arguments: *none*. +- Returns: `boolean`. + +The HOC, `withLoggingIn(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the stateful value, `loggingIn`. + +- Arguments: + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| Component | `React.ComponentType` | yes | A React component. | + +- Returns: `React.ForwardRefExoticComponent`. + +Examples: + +```tsx +import React from 'react'; +import { useLoggingIn, withLoggingIn } from 'meteor/react-meteor-accounts'; + +// Hook +function Foo() { + const loggingIn = useLoggingIn(); + + if (!loggingIn) { + return null; + } + + return ( +

Logging in, please wait a moment.
+ ); +} + +// HOC +class Bar extends React.Component { + render() { + if (!this.props.loggingIn) { + return null; + } + + return ( +
Logging in, please wait a moment.
+ ); + } +} + +const BarWithLoggingIn = withLoggingIn(Bar); +``` + +TypeScript signatures: + +```ts +// Hook +function useLoggingIn(): boolean; + +// HOC +function withLoggingIn

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +``` + +### useLoggingOut() / withLoggingOut(...) + +Get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut` (no online documentation), a reactive data source. + +The hook, `useLoggingOut()`, returns the stateful value. + +- Arguments: *none*. +- Returns: `boolean`. + +The HOC, `withLoggingOut(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the stateful value, `loggingOut`. + +- Arguments: + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| Component | `React.ComponentType` | yes | A React component. | + +- Returns: `React.ForwardRefExoticComponent`. + +Examples: + +```tsx +import React from 'react'; +import { useLoggingOut, withLoggingOut } from 'meteor/react-meteor-accounts'; + +// Hook +function Foo() { + const loggingOut = useLoggingOut(); + + if (!loggingOut) { + return null; + } + + return ( +

Logging out in, please wait a moment.
+ ); +} + +// HOC +class Bar extends React.Component { + render() { + if (!this.props.loggingOut) { + return null; + } + + return ( +
Logging out, please wait a moment.
+ ); + } +} + +const BarWithLoggingOut = withLoggingOut(Bar); +``` + +TypeScript signatures: + +```ts +// Hook +function useLoggingOut(): boolean; + +// HOC +function withLoggingOut

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; ``` diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index ec90f6be..8facc24f 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -20,7 +20,6 @@ Package.onTest((api) => { api.use([ 'accounts-base', 'accounts-password', - 'react-accounts', 'tinytest', 'tracker', 'typescript', diff --git a/packages/react-meteor-accounts/types/react-accounts.d.ts b/packages/react-meteor-accounts/types/react-accounts.d.ts index b813f3db..0a90ab56 100644 --- a/packages/react-meteor-accounts/types/react-accounts.d.ts +++ b/packages/react-meteor-accounts/types/react-accounts.d.ts @@ -1,6 +1,57 @@ import { Meteor } from 'meteor/meteor'; import React from 'react'; +declare module 'meteor/meteor' { + module Meteor { + function loggingOut(): boolean; + } +} +/** + * Hook to get a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-userId + */ export declare function useUserId(): string | null; -export declare function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; +export interface WithUserIdProps { + userId: string | null; +} +/** + * HOC to forward a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-userId + */ +export declare function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +/** + * Hook to get a stateful value of the current user record. Uses `Meteor.user`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-user + */ export declare function useUser(): Meteor.User | null; -export declare function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & React.RefAttributes>; +export interface WithUserProps { + user: Meteor.User | null; +} +/** + * HOC to get a stateful value of the current user record. Uses `Meteor.user`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-user + */ +export declare function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +/** + * Hook to get a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses `Meteor.loggingIn`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingIn + */ +export declare function useLoggingIn(): boolean; +export interface WithLoggingInProps { + loggingIn: boolean; +} +/** + * HOC to forward a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses `Meteor.loggingIn`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingIn + */ +export declare function withLoggingIn

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +/** + * Hook to get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + */ +export declare function useLoggingOut(): boolean; +export interface WithLoggingOutProps { + loggingOut: boolean; +} +/** + * HOC to forward a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + */ +export declare function withLoggingOut

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; From 0f72139edec7a03a3ab8c1967c58200a8e816c7e Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 19:43:19 -0500 Subject: [PATCH 21/36] chore(docs): split docs of hooks and HOCs --- packages/react-meteor-accounts/README.md | 282 +++++++++++++---------- 1 file changed, 158 insertions(+), 124 deletions(-) diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md index d5c30154..d0c04f0f 100644 --- a/packages/react-meteor-accounts/README.md +++ b/packages/react-meteor-accounts/README.md @@ -8,8 +8,14 @@ Simple hooks and higher-order components (HOCs) for getting reactive, stateful v - [Peer npm dependencies](#peer-npm-dependencies) - [Changelog](#changelog) - [Usage](#usage) - - [`useUser` / `withUser`](#useuser--withUser) - - [`useUserId` / `withUserId`](#useuserid--withUserId) + - [`useUser`](#useuser) + - [`useUserId`](#useuserid) + - [`useLoggingIn`](#useloggingin) + - [`useLoggingOut`](#useloggingout) + - [`withUser`](#withuser) + - [`withUserId`](#withuserid) + - [`withLoggingIn`](#withloggingin) + - [`withLoggingOut`](#withloggingout) ## Installation @@ -39,32 +45,19 @@ Utilities for each data source are available for the two ways of writing React c _Note:_ All HOCs forward refs. -### useUser() / withUser(...) +### useUser() -Get a stateful value of the current user record. Uses [`Meteor.user`](https://docs.meteor.com/api/accounts.html#Meteor-user), a reactive data source. - -The hook, `useUser()`, returns a stateful value of the current user record. +Get a stateful value of the current user record. A hook. Uses [`Meteor.user`](https://docs.meteor.com/api/accounts.html#Meteor-user), a reactive data source. - Arguments: *none*. - Returns: `object | null`. -The HOC, `withUser(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the current user record, `user`. - -- Arguments: - -| Argument | Type | Required | Description | -| --- | --- | --- | --- | -| Component | `any` | yes | A React component. | - -- Returns: `React.ForwardRefExoticComponent`. - -Examples: +Example: ```tsx import React from 'react'; -import { useUser, withUser } from 'meteor/react-meteor-accounts'; +import { useUser } from 'meteor/react-meteor-accounts'; -// Hook function Foo() { const user = useUser(); @@ -74,41 +67,116 @@ function Foo() { return

Hello {user.username}

; } +``` -// HOC -class Bar extends React.Component { - render() { - if (this.props.user === null) { - return

Log in

; - } +TypeScript signature: - return

Hello {this.props.user.username}

; - } -} +```ts +function useUser(): Meteor.User | null; +``` + +### useUserId() + +Get a stateful value of the current user id. A hook. Uses [`Meteor.userId`](https://docs.meteor.com/api/accounts.html#Meteor-userId), a reactive data source. -const WrappedBar = withUser(Bar); +- Arguments: *none*. +- Returns: `string | null`. + +Example: + +```tsx +import React from 'react'; +import { useUserId } from 'meteor/react-meteor-accounts'; + +function Foo() { + const userId = useUserId(); + + return ( +
+

Account Details

+ {userId ? ( +

Your unique account id is {userId}.

+ ) : ( +

Log-in to view your account details.

+ )} +
+ ); +} ``` -TypeScript signatures: +TypeScript signature: ```ts -// Hook -function useUser(): Meteor.User | null; +function useUserId(): string | null; +``` -// HOC -function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +### useLoggingIn() + +Get a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. A hook. Uses [`Meteor.loggingIn`](https://docs.meteor.com/api/accounts.html#Meteor-loggingIn), a reactive data source. + +- Arguments: *none*. +- Returns: `boolean`. + +Example: + +```tsx +import React from 'react'; +import { useLoggingIn } from 'meteor/react-meteor-accounts'; + +function Foo() { + const loggingIn = useLoggingIn(); + + if (!loggingIn) { + return null; + } + + return ( +

Logging in, please wait a moment.
+ ); +} ``` -### useUserId() / withUserId(...) +TypeScript signature: + +```ts +function useLoggingIn(): boolean; +``` -Get a stateful value of the current user id. Uses [`Meteor.userId`](https://docs.meteor.com/api/accounts.html#Meteor-userId), a reactive data source. +### useLoggingOut() -The hook, `useUserId()`, returns a stateful value of the current user id. +Get a stateful value of whether the logout method is currently in progress. A hook. Uses `Meteor.loggingOut` (no online documentation), a reactive data source. - Arguments: *none*. -- Returns: `string | null`. +- Returns: `boolean`. + +Example: + +```tsx +import React from 'react'; +import { useLoggingOut } from 'meteor/react-meteor-accounts'; -The HOC, `withUserId(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the current user id, `userId`. +function Foo() { + const loggingOut = useLoggingOut(); + + if (!loggingOut) { + return null; + } + + return ( +
Logging out, please wait a moment.
+ ); +} +``` + +TypeScript signature: + +```ts +function useLoggingOut(): boolean; +``` + +### withUser(...) + +Return a wrapped version of the given component, where the component receives a stateful prop of the current user record, `user`. A higher-order component. Uses [`Meteor.user`](https://docs.meteor.com/api/accounts.html#Meteor-user), a reactive data source. - Arguments: @@ -122,26 +190,46 @@ Examples: ```tsx import React from 'react'; -import { useUserId, withUserId } from 'meteor/react-meteor-accounts'; +import { withUser } from 'meteor/react-meteor-accounts'; -// Hook -function Foo() { - const userId = useUserId(); +class Foo extends React.Component { + render() { + if (this.props.user === null) { + return

Log in

; + } - return ( -
-

Account Details

- {userId ? ( -

Your unique account id is {userId}.

- ) : ( -

Log-in to view your account details.

- )} -
- ); + return

Hello {this.props.user.username}

; + } } -// HOC -class Bar extends React.Component { +const FooWithUser = withUser(Foo); +``` + +TypeScript signature: + +```ts +function withUser

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; +``` + +### withUserId(...) + +Return a wrapped version of the given component, where the component receives a stateful prop of the current user id. A higher-order component. Uses [`Meteor.userId`](https://docs.meteor.com/api/accounts.html#Meteor-userId), a reactive data source. + +- Arguments: + +| Argument | Type | Required | Description | +| --- | --- | --- | --- | +| Component | `React.ComponentType` | yes | A React component. | + +- Returns: `React.ForwardRefExoticComponent`. + +Example: + +```tsx +import React from 'react'; +import { withUserId } from 'meteor/react-meteor-accounts'; + +class Foo extends React.Component { render() { return (

@@ -156,29 +244,18 @@ class Bar extends React.Component { } } -const WrappedBar = withUserId(Bar); +const FooWithUserId = withUserId(Foo); ``` -TypeScript signatures: +TypeScript signature: ```ts -// Hook -function useUserId(): string | null; - -// HOC function withUserId

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; ``` -### useLoggingIn() / withLoggingIn(...) - -Get a stateful value of whether a login method (e.g. `loginWith`) is currently in progress. Uses [`Meteor.loggingIn`](https://docs.meteor.com/api/accounts.html#Meteor-loggingIn), a reactive data source. +### withLoggingIn(...) -The hook, `useLoggingIn()`, returns the stateful value. - -- Arguments: *none*. -- Returns: `boolean`. - -The HOC, `withLoggingIn(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the stateful value, `loggingIn`. +Return a wrapped version of the given component, where the component receives a stateful prop of whether a login method (e.g. `loginWith`) is currently in progress. A higher-order component. Uses [`Meteor.loggingIn`](https://docs.meteor.com/api/accounts.html#Meteor-loggingIn), a reactive data source. - Arguments: @@ -188,27 +265,13 @@ The HOC, `withLoggingIn(Component)`, returns a wrapped version of `Component`, w - Returns: `React.ForwardRefExoticComponent`. -Examples: +Example: ```tsx import React from 'react'; -import { useLoggingIn, withLoggingIn } from 'meteor/react-meteor-accounts'; - -// Hook -function Foo() { - const loggingIn = useLoggingIn(); - - if (!loggingIn) { - return null; - } - - return ( -

Logging in, please wait a moment.
- ); -} +import { withLoggingIn } from 'meteor/react-meteor-accounts'; -// HOC -class Bar extends React.Component { +class Foo extends React.Component { render() { if (!this.props.loggingIn) { return null; @@ -220,29 +283,18 @@ class Bar extends React.Component { } } -const BarWithLoggingIn = withLoggingIn(Bar); +const FooWithLoggingIn = withLoggingIn(Foo); ``` TypeScript signatures: ```ts -// Hook -function useLoggingIn(): boolean; - -// HOC function withLoggingIn

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; ``` -### useLoggingOut() / withLoggingOut(...) - -Get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut` (no online documentation), a reactive data source. +### withLoggingOut(...) -The hook, `useLoggingOut()`, returns the stateful value. - -- Arguments: *none*. -- Returns: `boolean`. - -The HOC, `withLoggingOut(Component)`, returns a wrapped version of `Component`, where `Component` receives a prop of the stateful value, `loggingOut`. +Return a wrapped version of the given component, where the component receives a stateful prop of whether the logout method is currently in progress. A higher-order component. Uses `Meteor.loggingOut` (no online documentation), a reactive data source. - Arguments: @@ -252,27 +304,13 @@ The HOC, `withLoggingOut(Component)`, returns a wrapped version of `Component`, - Returns: `React.ForwardRefExoticComponent`. -Examples: +Example: ```tsx import React from 'react'; -import { useLoggingOut, withLoggingOut } from 'meteor/react-meteor-accounts'; - -// Hook -function Foo() { - const loggingOut = useLoggingOut(); +import { withLoggingOut } from 'meteor/react-meteor-accounts'; - if (!loggingOut) { - return null; - } - - return ( -

Logging out in, please wait a moment.
- ); -} - -// HOC -class Bar extends React.Component { +class Foo extends React.Component { render() { if (!this.props.loggingOut) { return null; @@ -284,15 +322,11 @@ class Bar extends React.Component { } } -const BarWithLoggingOut = withLoggingOut(Bar); +const FooWithLoggingOut = withLoggingOut(Foo); ``` -TypeScript signatures: +TypeScript signature: ```ts -// Hook -function useLoggingOut(): boolean; - -// HOC function withLoggingOut

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; ``` From e7f4bcc356e92d664fab468e97515ddbedd367f9 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 23:09:56 -0500 Subject: [PATCH 22/36] fix: re-export all utils from index --- packages/react-meteor-accounts/index.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/react-meteor-accounts/index.ts b/packages/react-meteor-accounts/index.ts index 074d0fd5..e5800631 100644 --- a/packages/react-meteor-accounts/index.ts +++ b/packages/react-meteor-accounts/index.ts @@ -9,4 +9,13 @@ if (Meteor.isDevelopment) { } } -export { useUser, withUser, useUserId, withUserId } from './react-accounts'; +export { + useUser, + useUserId, + useLoggingIn, + useLoggingOut, + withUser, + withUserId, + withLoggingIn, + withLoggingOut +} from './react-accounts'; From e2961e46d2a11f6578c2c8a2f388e7b4fd73bc81 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Tue, 14 Dec 2021 23:11:36 -0500 Subject: [PATCH 23/36] fix: correct package name in warning --- packages/react-meteor-accounts/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-meteor-accounts/index.ts b/packages/react-meteor-accounts/index.ts index e5800631..a7312bdf 100644 --- a/packages/react-meteor-accounts/index.ts +++ b/packages/react-meteor-accounts/index.ts @@ -5,7 +5,7 @@ if (Meteor.isDevelopment) { // Custom check instead of `checkNpmVersions` to reduce prod bundle size (~8kb). const v = React.version.split('.').map(val => parseInt(val)); if (v[0] < 16 || (v[0] === 16 && v[1] < 8)) { - console.warn('react-meteor-accounts requires React version >= 16.8.'); + console.warn('react-accounts requires React version >= 16.8.'); } } From 1717057abbc6968e56b8f9299759c130c2b4c99f Mon Sep 17 00:00:00 2001 From: William Kelley Date: Wed, 22 Dec 2021 00:21:03 -0700 Subject: [PATCH 24/36] fix(internal): missing null union in return types --- packages/react-meteor-accounts/package-lock.json | 6 ++++++ packages/react-meteor-accounts/package.json | 3 ++- packages/react-meteor-accounts/react-accounts.tsx | 6 +++--- packages/react-meteor-accounts/tsconfig.json | 6 ++++++ 4 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 packages/react-meteor-accounts/tsconfig.json diff --git a/packages/react-meteor-accounts/package-lock.json b/packages/react-meteor-accounts/package-lock.json index abdc6559..da1779fa 100644 --- a/packages/react-meteor-accounts/package-lock.json +++ b/packages/react-meteor-accounts/package-lock.json @@ -124,6 +124,12 @@ } } }, + "@tsconfig/recommended": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/recommended/-/recommended-1.0.1.tgz", + "integrity": "sha512-2xN+iGTbPBEzGSnVp/Hd64vKJCJWxsi9gfs88x4PPMyEjHJoA3o5BY9r5OLPHIZU2pAQxkSAsJFqn6itClP8mQ==", + "dev": true + }, "@types/aria-query": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz", diff --git a/packages/react-meteor-accounts/package.json b/packages/react-meteor-accounts/package.json index 8dc3e3e6..4f38b650 100644 --- a/packages/react-meteor-accounts/package.json +++ b/packages/react-meteor-accounts/package.json @@ -1,11 +1,12 @@ { "name": "meteor-react-accounts", "scripts": { - "make-types": "npx typescript *.tsx --jsx preserve --declaration --emitDeclarationOnly --esModuleInterop --outDir types" + "make-types": "npx typescript react-accounts.tsx --jsx preserve --declaration --emitDeclarationOnly --esModuleInterop --outDir types --strict" }, "devDependencies": { "@testing-library/react": "^10.0.2", "@testing-library/react-hooks": "^7.0.2", + "@tsconfig/recommended": "^1.0.1", "@types/meteor": "^1.4.42", "@types/react": "^16.9.34", "react": "16.13.1", diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 020806d2..f96d3217 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -13,7 +13,7 @@ declare module 'meteor/meteor' { * Hook to get a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-userId */ -export function useUserId(): string | null { +export function useUserId() { const [userId, setUserId] = useState(Meteor.userId()) useEffect(() => { const computation = Tracker.autorun(() => { @@ -55,7 +55,7 @@ export function withUserId

(Component: React.ComponentType

) { * Hook to get a stateful value of the current user record. Uses `Meteor.user`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-user */ -export function useUser(): Meteor.User | null { +export function useUser() { const [user, setUser] = useState(Meteor.user()); useEffect(() => { const computation = Tracker.autorun(() => { @@ -74,7 +74,7 @@ export function useUser(): Meteor.User | null { } export interface WithUserProps { - user: Meteor.User | null; + user: Meteor.User; } /** diff --git a/packages/react-meteor-accounts/tsconfig.json b/packages/react-meteor-accounts/tsconfig.json new file mode 100644 index 00000000..1cb0c5fb --- /dev/null +++ b/packages/react-meteor-accounts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@tsconfig/recommended/tsconfig.json", + "compilerOptions": { + "jsx": "preserve" + } +} \ No newline at end of file From 0bac6826027d2037bda4a4559afb256a8eae8a89 Mon Sep 17 00:00:00 2001 From: William Kelley Date: Thu, 23 Dec 2021 15:59:08 -0700 Subject: [PATCH 25/36] fix(types): remove unnecessary module aug. & add null union for `user` --- packages/react-meteor-accounts/react-accounts.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index f96d3217..13516461 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -2,13 +2,6 @@ import { Meteor } from 'meteor/meteor' import { Tracker } from 'meteor/tracker' import React, { useState, useEffect, forwardRef } from 'react' -// Augmentation to add missing signature -declare module 'meteor/meteor' { - module Meteor { - function loggingOut(): boolean; - } -} - /** * Hook to get a stateful value of the current user id. Uses `Meteor.userId`, a reactive data source. * @see https://docs.meteor.com/api/accounts.html#Meteor-userId @@ -74,7 +67,7 @@ export function useUser() { } export interface WithUserProps { - user: Meteor.User; + user: Meteor.User | null; } /** From 4553c1134c04e7e9be450655c7e6d37732979421 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 15:03:00 -0500 Subject: [PATCH 26/36] Update CHANGELOG.md --- packages/react-meteor-accounts/CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/react-meteor-accounts/CHANGELOG.md b/packages/react-meteor-accounts/CHANGELOG.md index 5a77c659..d7c9345d 100644 --- a/packages/react-meteor-accounts/CHANGELOG.md +++ b/packages/react-meteor-accounts/CHANGELOG.md @@ -2,6 +2,14 @@ Release versions follow [Semantic Versioning 2.0.0 guidelines](https://semver.org/). +## v1.0.0-beta.2 + +- `useLogginIn`: Added implementation +- `useLogginOut`: Added implementation +- `withLogginIn`: Added implementation +- `withLogginOut`: Added implementation +- improved tests and readme + ## v1.0.0-beta.1 2021-10-20 (date of last commit) From b4ac6903a497381e86a6e8da6a7c1f53660b2994 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:30:59 -0500 Subject: [PATCH 27/36] fix typos in packages/react-meteor-accounts/CHANGELOG.md Co-authored-by: William Kelley --- packages/react-meteor-accounts/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-meteor-accounts/CHANGELOG.md b/packages/react-meteor-accounts/CHANGELOG.md index d7c9345d..be3ec70b 100644 --- a/packages/react-meteor-accounts/CHANGELOG.md +++ b/packages/react-meteor-accounts/CHANGELOG.md @@ -4,10 +4,10 @@ Release versions follow [Semantic Versioning 2.0.0 guidelines](https://semver.or ## v1.0.0-beta.2 -- `useLogginIn`: Added implementation -- `useLogginOut`: Added implementation -- `withLogginIn`: Added implementation -- `withLogginOut`: Added implementation +- `useLoggingIn`: Added implementation +- `useLoggingOut`: Added implementation +- `withLoggingIn`: Added implementation +- `withLoggingOut`: Added implementation - improved tests and readme ## v1.0.0-beta.1 From afb08c4660bcedd3ee4811cc0888577f9de5f26a Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:32:06 -0500 Subject: [PATCH 28/36] Update summary in packages/react-meteor-accounts/package.js Adds note about HOCs Co-authored-by: William Kelley --- packages/react-meteor-accounts/package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index 8facc24f..b4bab541 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -2,7 +2,7 @@ Package.describe({ name: 'react-accounts', - summary: 'React hook for reactively tracking Meteor Accounts data', + summary: 'React hooks and HOCs for reactively tracking Meteor Accounts data', version: '1.0.0-beta.1', documentation: 'README.md', git: 'https://github.com/meteor/react-packages', From 1b5d10a217d65d7c3c31994938358d72def28434 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:32:54 -0500 Subject: [PATCH 29/36] Add links to Meteor-logginOut in packages/react-meteor-accounts/README.md Co-authored-by: William Kelley --- packages/react-meteor-accounts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md index d0c04f0f..e9d41be6 100644 --- a/packages/react-meteor-accounts/README.md +++ b/packages/react-meteor-accounts/README.md @@ -294,7 +294,7 @@ function withLoggingIn

(Component: React.ComponentType

): React.ForwardRefEx ### withLoggingOut(...) -Return a wrapped version of the given component, where the component receives a stateful prop of whether the logout method is currently in progress. A higher-order component. Uses `Meteor.loggingOut` (no online documentation), a reactive data source. +Return a wrapped version of the given component, where the component receives a stateful prop of whether the logout method is currently in progress. A higher-order component. Uses [`Meteor.loggingOut`](https://docs.meteor.com/api/accounts.html#Meteor-loggingOut), a reactive data source. - Arguments: From 431366ade42ff06b7015ecfef8685ef56097f32b Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:33:01 -0500 Subject: [PATCH 30/36] Update packages/react-meteor-accounts/react-accounts.tsx Co-authored-by: William Kelley --- packages/react-meteor-accounts/react-accounts.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 13516461..4fd3cb72 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -124,6 +124,7 @@ export function withLoggingIn

(Component: React.ComponentType

) { /** * Hook to get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingOut */ export function useLoggingOut(): boolean { const [loggingOut, setLoggingOut] = useState(Meteor.loggingOut()); From e3cda86dd8dccd1e3b3ce323c818a733fd966384 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:33:08 -0500 Subject: [PATCH 31/36] Update packages/react-meteor-accounts/types/react-accounts.d.ts Co-authored-by: William Kelley --- packages/react-meteor-accounts/types/react-accounts.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-meteor-accounts/types/react-accounts.d.ts b/packages/react-meteor-accounts/types/react-accounts.d.ts index 0a90ab56..333f164a 100644 --- a/packages/react-meteor-accounts/types/react-accounts.d.ts +++ b/packages/react-meteor-accounts/types/react-accounts.d.ts @@ -46,6 +46,7 @@ export interface WithLoggingInProps { export declare function withLoggingIn

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; /** * Hook to get a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingOut */ export declare function useLoggingOut(): boolean; export interface WithLoggingOutProps { From 41fc70f21d4cf6d25b42ff18aaea9a063c1da7a4 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:33:17 -0500 Subject: [PATCH 32/36] Update packages/react-meteor-accounts/types/react-accounts.d.ts Co-authored-by: William Kelley --- packages/react-meteor-accounts/types/react-accounts.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-meteor-accounts/types/react-accounts.d.ts b/packages/react-meteor-accounts/types/react-accounts.d.ts index 333f164a..bb5a5a84 100644 --- a/packages/react-meteor-accounts/types/react-accounts.d.ts +++ b/packages/react-meteor-accounts/types/react-accounts.d.ts @@ -54,5 +54,6 @@ export interface WithLoggingOutProps { } /** * HOC to forward a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingOut */ export declare function withLoggingOut

(Component: React.ComponentType

): React.ForwardRefExoticComponent & Partial> & React.RefAttributes>; From 90856734667b93c2cae253b96033dd9a291ddff0 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:33:25 -0500 Subject: [PATCH 33/36] Update packages/react-meteor-accounts/react-accounts.tsx Co-authored-by: William Kelley --- packages/react-meteor-accounts/react-accounts.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-meteor-accounts/react-accounts.tsx b/packages/react-meteor-accounts/react-accounts.tsx index 4fd3cb72..1e681f32 100644 --- a/packages/react-meteor-accounts/react-accounts.tsx +++ b/packages/react-meteor-accounts/react-accounts.tsx @@ -145,6 +145,7 @@ export interface WithLoggingOutProps { /** * HOC to forward a stateful value of whether the logout method is currently in progress. Uses `Meteor.loggingOut`, a reactive data source. + * @see https://docs.meteor.com/api/accounts.html#Meteor-loggingOut */ export function withLoggingOut

(Component: React.ComponentType

) { return forwardRef( From 4d8149f17a4f3fb21e223399c47ae3f91591e3b7 Mon Sep 17 00:00:00 2001 From: Kevin Newman Date: Fri, 28 Jan 2022 22:37:05 -0500 Subject: [PATCH 34/36] Change release version to rc.1 in CHANGELOG.md --- packages/react-meteor-accounts/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-meteor-accounts/CHANGELOG.md b/packages/react-meteor-accounts/CHANGELOG.md index be3ec70b..6a16211b 100644 --- a/packages/react-meteor-accounts/CHANGELOG.md +++ b/packages/react-meteor-accounts/CHANGELOG.md @@ -2,7 +2,7 @@ Release versions follow [Semantic Versioning 2.0.0 guidelines](https://semver.org/). -## v1.0.0-beta.2 +## v1.0.0-rc.1 - `useLoggingIn`: Added implementation - `useLoggingOut`: Added implementation From 0e4cc21e4d8e0f54a35184d0b58776318cd4fcbc Mon Sep 17 00:00:00 2001 From: denihs Date: Wed, 23 Feb 2022 14:14:16 -0400 Subject: [PATCH 35/36] updating information inside package.js --- packages/react-meteor-accounts/package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index b4bab541..f5deac38 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -1,9 +1,9 @@ /* global Package */ Package.describe({ - name: 'react-accounts', + name: 'react-meteor-accounts', summary: 'React hooks and HOCs for reactively tracking Meteor Accounts data', - version: '1.0.0-beta.1', + version: '1.0.0', documentation: 'README.md', git: 'https://github.com/meteor/react-packages', }); From f5feaad5a0a84965077a74bdfcfc6e37dd26826a Mon Sep 17 00:00:00 2001 From: denihs Date: Wed, 23 Feb 2022 17:25:18 -0400 Subject: [PATCH 36/36] - Changing package name so we can publish it as a core package - updating package name in the README.md --- packages/react-meteor-accounts/README.md | 18 +++++++++--------- packages/react-meteor-accounts/package.js | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/react-meteor-accounts/README.md b/packages/react-meteor-accounts/README.md index e9d41be6..f6102d42 100644 --- a/packages/react-meteor-accounts/README.md +++ b/packages/react-meteor-accounts/README.md @@ -22,7 +22,7 @@ Simple hooks and higher-order components (HOCs) for getting reactive, stateful v Install the package from Atmosphere: ```shell -meteor add react-meteor-accounts +meteor add mdg:react-meteor-accounts ``` ### Peer npm dependencies @@ -56,7 +56,7 @@ Example: ```tsx import React from 'react'; -import { useUser } from 'meteor/react-meteor-accounts'; +import { useUser } from 'meteor/mdg:react-meteor-accounts'; function Foo() { const user = useUser(); @@ -86,7 +86,7 @@ Example: ```tsx import React from 'react'; -import { useUserId } from 'meteor/react-meteor-accounts'; +import { useUserId } from 'meteor/mdg:react-meteor-accounts'; function Foo() { const userId = useUserId(); @@ -121,7 +121,7 @@ Example: ```tsx import React from 'react'; -import { useLoggingIn } from 'meteor/react-meteor-accounts'; +import { useLoggingIn } from 'meteor/mdg:react-meteor-accounts'; function Foo() { const loggingIn = useLoggingIn(); @@ -153,7 +153,7 @@ Example: ```tsx import React from 'react'; -import { useLoggingOut } from 'meteor/react-meteor-accounts'; +import { useLoggingOut } from 'meteor/mdg:react-meteor-accounts'; function Foo() { const loggingOut = useLoggingOut(); @@ -190,7 +190,7 @@ Examples: ```tsx import React from 'react'; -import { withUser } from 'meteor/react-meteor-accounts'; +import { withUser } from 'meteor/mdg:react-meteor-accounts'; class Foo extends React.Component { render() { @@ -227,7 +227,7 @@ Example: ```tsx import React from 'react'; -import { withUserId } from 'meteor/react-meteor-accounts'; +import { withUserId } from 'meteor/mdg:react-meteor-accounts'; class Foo extends React.Component { render() { @@ -269,7 +269,7 @@ Example: ```tsx import React from 'react'; -import { withLoggingIn } from 'meteor/react-meteor-accounts'; +import { withLoggingIn } from 'meteor/mdg:react-meteor-accounts'; class Foo extends React.Component { render() { @@ -308,7 +308,7 @@ Example: ```tsx import React from 'react'; -import { withLoggingOut } from 'meteor/react-meteor-accounts'; +import { withLoggingOut } from 'meteor/mdg:react-meteor-accounts'; class Foo extends React.Component { render() { diff --git a/packages/react-meteor-accounts/package.js b/packages/react-meteor-accounts/package.js index f5deac38..151eafe5 100644 --- a/packages/react-meteor-accounts/package.js +++ b/packages/react-meteor-accounts/package.js @@ -1,7 +1,7 @@ /* global Package */ Package.describe({ - name: 'react-meteor-accounts', + name: 'mdg:react-meteor-accounts', summary: 'React hooks and HOCs for reactively tracking Meteor Accounts data', version: '1.0.0', documentation: 'README.md',