├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── LICENSE ├── example ├── App.vue ├── components │ ├── dnd.vue │ ├── json.vue │ └── markdown.vue ├── files.d.ts ├── index.html ├── index.tsx ├── kbar.ts ├── react-input.ts ├── react-props.ts ├── tsconfig.json ├── types.d.ts └── xlog.tsx ├── package.json ├── pnpm-lock.yaml ├── readme.md ├── renovate.json ├── rollup.config.js ├── src ├── global.d.ts ├── index.ts ├── libs │ ├── react-dom.ts │ └── react.ts ├── react-types │ └── react │ │ ├── package.json │ │ └── react.d.ts ├── tsconfig.build.json ├── tsconfig.cjs.json ├── tsconfig.json ├── utils │ └── index.ts └── wrapper.ts ├── tsconfig.json ├── vite.config.js └── vitest.config.ts /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | // if need react 4 | // "@babel/preset-react" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/react-types/** 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | es6: true, 7 | }, 8 | extends: ['@innei-util/eslint-config-react-ts'], 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x, 16.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v2 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: Cache pnpm modules 27 | uses: actions/cache@v2 28 | env: 29 | cache-name: cache-pnpm-modules 30 | with: 31 | path: ~/.pnpm-store 32 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}-${{ hashFiles('**/package.json') }} 33 | restore-keys: | 34 | ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.node-version }}- 35 | 36 | - uses: pnpm/action-setup@v2.0.1 37 | with: 38 | version: 6.0.2 39 | run_install: true 40 | - run: pnpm run package 41 | - run: pnpm run test 42 | env: 43 | CI: true 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | node_modules 3 | /node_modules 4 | .DS_Store 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # Snowpack dependency directory (https://snowpack.dev/) 49 | web_modules/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | 85 | # Gatsby files 86 | .cache/ 87 | 88 | # vuepress build output 89 | .vuepress/dist 90 | 91 | # Serverless directories 92 | .serverless/ 93 | 94 | # FuseBox cache 95 | .fusebox/ 96 | 97 | # DynamoDB Local files 98 | .dynamodb/ 99 | 100 | # TernJS port file 101 | .tern-port 102 | 103 | # Stores VSCode versions used for testing VSCode extensions 104 | .vscode-test 105 | 106 | # yarn v2 107 | 108 | .yarn/cache 109 | .yarn/unplugged 110 | .yarn/build-state.yml 111 | .pnp.* 112 | 113 | # vim 114 | ctag 115 | /tags 116 | .undodir 117 | 118 | # idea 119 | # .idea/* 120 | 121 | /dist 122 | /publish 123 | /build 124 | /lib 125 | /esm 126 | /types 127 | 128 | example/dist 129 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/react-types/** 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@innei-util/prettier') 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Innei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 93 | -------------------------------------------------------------------------------- /example/components/dnd.vue: -------------------------------------------------------------------------------- 1 | 193 | 194 | 197 | -------------------------------------------------------------------------------- /example/components/json.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 47 | -------------------------------------------------------------------------------- /example/components/markdown.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | -------------------------------------------------------------------------------- /example/files.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite 8 | 9 | 10 |
Hello!
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/index.tsx: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | 3 | import 'uno.css' 4 | 5 | import App from './App.vue' 6 | 7 | createApp(App).mount('#app') 8 | -------------------------------------------------------------------------------- /example/kbar.ts: -------------------------------------------------------------------------------- 1 | import { 2 | KBarAnimator, 3 | KBarPortal, 4 | KBarPositioner, 5 | KBarProvider, 6 | KBarSearch, 7 | } from 'kbar' 8 | 9 | import React from '~/react-types/react/react' 10 | 11 | export const KBar = () => { 12 | return React.createElement(KBarProvider, { 13 | actions: [ 14 | { 15 | id: 'blog', 16 | name: 'Blog', 17 | shortcut: ['b'], 18 | keywords: 'writing words', 19 | perform: () => (window.location.pathname = 'blog'), 20 | }, 21 | { 22 | id: 'contact', 23 | name: 'Contact', 24 | shortcut: ['c'], 25 | keywords: 'email', 26 | perform: () => (window.location.pathname = 'contact'), 27 | }, 28 | ], 29 | children: [ 30 | React.createElement(KBarPortal, { 31 | children: [ 32 | React.createElement(KBarPositioner, { 33 | children: [ 34 | React.createElement(KBarAnimator, { 35 | children: [React.createElement(KBarSearch, {})], 36 | }), 37 | ], 38 | }), 39 | ], 40 | }), 41 | React.createElement('div', { 42 | style: { 43 | height: '100vh', 44 | }, 45 | }), 46 | ], 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /example/react-input.ts: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, useEffect, useState } from 'react' 2 | 3 | export type ReactInputProps = { value: string; onChange: any } 4 | export const ReactInput = forwardRef( 5 | (props, ref) => { 6 | const [state, setState] = useState(props) 7 | // useImperativeHandle(ref, () => { 8 | // return { 9 | // onPropsChange: (props: ReactInputProps) => { 10 | // setState(props) 11 | // }, 12 | // } 13 | // }) 14 | useEffect(() => { 15 | setState(props) 16 | }, [props]) 17 | return React.createElement('input', { 18 | value: state.value, 19 | onChange: state.onChange, 20 | ref, 21 | }) 22 | }, 23 | ) 24 | -------------------------------------------------------------------------------- /example/react-props.ts: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, useImperativeHandle } from 'react' 2 | 3 | export const List = forwardRef<{}, { data: string[]; onChange: any }>( 4 | (props, ref) => { 5 | useImperativeHandle( 6 | () => ref, 7 | () => ({ 8 | get() { 9 | return props.data 10 | }, 11 | }), 12 | ) 13 | 14 | return React.createElement('div', null, [ 15 | React.createElement( 16 | 'ul', 17 | null, 18 | props.data.map((item) => 19 | React.createElement('li', { key: item }, item), 20 | ), 21 | ), 22 | 23 | React.createElement('div', { style: { display: 'flex', gap: '2rem' } }, [ 24 | React.createElement( 25 | 'button', 26 | { 27 | onClick() { 28 | props.onChange([...props.data, props.data.length.toString()]) 29 | }, 30 | }, 31 | 'add', 32 | ), 33 | 34 | props.children, 35 | ]), 36 | ]) 37 | }, 38 | ) 39 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "jsx": "preserve", 6 | "paths": { 7 | "~/*": ["../src/*"], 8 | "~": ["../src"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/types.d.ts: -------------------------------------------------------------------------------- 1 | import 'vite/client' 2 | 3 | export {} 4 | -------------------------------------------------------------------------------- /example/xlog.tsx: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import React, { forwardRef, useImperativeHandle } from 'react' 3 | import Unidata from 'unidata.js' 4 | import { WagmiConfig, createClient, useAccount } from 'wagmi' 5 | 6 | import { 7 | ConnectKitProvider, 8 | getDefaultClientConfig, 9 | useAccountState, 10 | useConnectModal, 11 | } from '@crossbell/connect-kit' 12 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 13 | 14 | export { useAccount } from 'wagmi' 15 | export { useAccountState, useConnectModal } from '@crossbell/connect-kit' 16 | 17 | const IPFS_PREFIX = 'ipfs://' 18 | const IPFS_GATEWAY = 'https://ipfs.4everland.xyz/ipfs/' 19 | const CSB_IO = 'https://crossbell.io' 20 | const OUR_DOMAIN = 'xlog.app' 21 | 22 | const namespace = 'xlog' 23 | let data = {} 24 | try { 25 | data = JSON.parse(localStorage.getItem(namespace) || '{}') 26 | // eslint-disable-next-line no-empty 27 | } catch (error) {} 28 | const getKeys = (key) => { 29 | return Object.keys(data).filter((k) => k.startsWith(key)) 30 | } 31 | const getStorage = (key) => { 32 | return data[key] 33 | } 34 | 35 | const getLocalPages = (input) => { 36 | const pages = [] 37 | getKeys(`draft-${input.site}-`).forEach((key) => { 38 | const page = getStorage(key) 39 | if (input.isPost === undefined || page.isPost === input.isPost) { 40 | pages.push({ 41 | id: key.replace(`draft-${input.site}-`, ''), 42 | title: page.values?.title, 43 | body: { 44 | content: page.values?.content, 45 | mime_type: 'text/markdown', 46 | }, 47 | date_updated: new Date(page.date).toISOString(), 48 | date_published: page.values?.publishedAt, 49 | summary: { 50 | content: page.values?.excerpt, 51 | mime_type: 'text/markdown', 52 | }, 53 | tags: [ 54 | page.isPost ? 'post' : 'page', 55 | ...(page.values?.tags 56 | ?.split(',') 57 | .map((tag) => tag.trim()) 58 | .filter((tag) => tag) || []), 59 | ], 60 | applications: ['xlog'], 61 | ...(page.values?.slug && { 62 | attributes: [ 63 | { 64 | trait_type: 'xlog_slug', 65 | value: page.values?.slug, 66 | }, 67 | ], 68 | }), 69 | preview: true, 70 | }) 71 | } 72 | }) 73 | return pages 74 | } 75 | async function createOrUpdatePage(input, customUnidata, newbieToken) { 76 | if (!input.published) { 77 | return await customUnidata.notes.set( 78 | { 79 | source: 'Crossbell Note', 80 | identity: input.siteId, 81 | platform: 'Crossbell', 82 | action: 'remove', 83 | }, 84 | { 85 | id: input.pageId, 86 | }, 87 | { 88 | newbieToken, 89 | }, 90 | ) 91 | } 92 | return await customUnidata.notes.set( 93 | { 94 | source: 'Crossbell Note', 95 | identity: input.siteId, 96 | platform: 'Crossbell', 97 | action: input.pageId ? 'update' : 'add', 98 | }, 99 | { 100 | ...(input.externalUrl && { related_urls: [input.externalUrl] }), 101 | ...(input.pageId && { id: input.pageId }), 102 | ...(input.title && { title: input.title }), 103 | ...(input.content && { 104 | body: { 105 | content: input.content, 106 | mime_type: 'text/markdown', 107 | }, 108 | }), 109 | ...(input.publishedAt && { 110 | date_published: input.publishedAt, 111 | }), 112 | ...(input.excerpt && { 113 | summary: { 114 | content: input.excerpt, 115 | mime_type: 'text/markdown', 116 | }, 117 | }), 118 | tags: [ 119 | input.isPost ? 'post' : 'page', 120 | ...(input.tags 121 | ?.split(',') 122 | .map((tag) => tag.trim()) 123 | .filter((tag) => tag) || []), 124 | ], 125 | applications: [ 126 | 'xlog', 127 | ...(input.applications?.filter((app) => app !== 'xlog') || []), 128 | ], 129 | ...(input.slug && { 130 | attributes: [ 131 | { 132 | trait_type: 'xlog_slug', 133 | value: input.slug, 134 | }, 135 | ], 136 | }), 137 | }, 138 | { 139 | newbieToken, 140 | }, 141 | ) 142 | } 143 | async function getPage(input, customUnidata) { 144 | if (!input.site || !(input.page || input.pageId)) { 145 | return null 146 | } 147 | const mustLocal = input.pageId?.startsWith('local-') 148 | let page = null 149 | if (!mustLocal) { 150 | // on-chain page 151 | if (!input.pageId) { 152 | const params = new URLSearchParams() 153 | params.append('handle', input.site) 154 | input.page && params.append('slug', input.page) 155 | const slug2Id = await fetch( 156 | `https://xlog.app` + `/api/slug2id?${params.toString()}`, 157 | ).then((res) => res.json()) 158 | if (!slug2Id?.noteId) { 159 | return null 160 | } 161 | input.pageId = `${slug2Id.characterId}-${slug2Id.noteId}` 162 | } 163 | const pages = await customUnidata.notes.get({ 164 | source: 'Crossbell Note', 165 | identity: input.site, 166 | platform: 'Crossbell', 167 | filter: { 168 | id: input.pageId, 169 | }, 170 | }) 171 | page = pages?.list[0] || null 172 | } 173 | // local page 174 | const local = getLocalPages({ 175 | site: input.site, 176 | }) 177 | const localPage = local.find( 178 | (page) => page.id === input.page || page.id === input.pageId, 179 | ) 180 | if (localPage) { 181 | if (page) { 182 | if (new Date(localPage.date_updated) > new Date(page.date_updated)) { 183 | localPage.metadata = page.metadata 184 | page = localPage 185 | } 186 | } else { 187 | page = localPage 188 | } 189 | } 190 | return page 191 | } 192 | 193 | let unidata 194 | const useUnidata = () => { 195 | const { connector, isConnected } = useAccount() 196 | if (isConnected && connector) { 197 | connector?.getProvider().then((provider) => { 198 | unidata = new Unidata({ 199 | ethereumProvider: provider, 200 | ipfsGateway: IPFS_GATEWAY, 201 | }) 202 | }) 203 | } else { 204 | unidata = new Unidata({ 205 | ipfsGateway: IPFS_GATEWAY, 206 | }) 207 | } 208 | return unidata 209 | } 210 | function useCreateOrUpdatePage() { 211 | const newbieToken = useAccountState((s) => s.email?.token) 212 | const unidata = useUnidata() 213 | return (payload) => createOrUpdatePage(payload, unidata, newbieToken) 214 | } 215 | 216 | const toGateway = (url) => { 217 | const ipfsUrl = toIPFS(url) 218 | return ipfsUrl?.replaceAll(IPFS_PREFIX, IPFS_GATEWAY) 219 | } 220 | const toIPFS = (url) => { 221 | return url 222 | ?.replaceAll(IPFS_GATEWAY, IPFS_PREFIX) 223 | .replaceAll('https://gateway.ipfs.io/ipfs/', IPFS_PREFIX) 224 | .replaceAll('https://ipfs.io/ipfs/', IPFS_PREFIX) 225 | .replaceAll('https://cf-ipfs.com/ipfs/', IPFS_PREFIX) 226 | .replaceAll('https://ipfs.4everland.xyz/ipfs/', IPFS_PREFIX) 227 | .replaceAll('https://rss3.mypinata.cloud/ipfs/', IPFS_PREFIX) 228 | } 229 | 230 | const getSiteLink = ({ domain, subdomain, noProtocol }) => { 231 | if (domain) { 232 | return `https://${domain}` 233 | } 234 | if (noProtocol) { 235 | return `${subdomain}.${OUR_DOMAIN}` 236 | } 237 | return `https://${subdomain}.${OUR_DOMAIN}` 238 | } 239 | const getNoteSlug = (note) => { 240 | return ( 241 | note.metadata?.content?.attributes?.find( 242 | (a) => a?.trait_type === 'xlog_slug', 243 | )?.value || 244 | note.metadata?.content?._xlog_slug || 245 | note.metadata?.content?._crosslog_slug 246 | )?.toLowerCase?.() 247 | } 248 | 249 | const urlComposer = { 250 | characterUrl: ({ handle }) => getSiteLink({ subdomain: handle }), 251 | noteUrl: (note) => { 252 | let originalNote = note 253 | while (originalNote?.toNote) { 254 | originalNote = originalNote.toNote 255 | } 256 | if (originalNote.metadata?.content?.sources?.includes('xlog')) { 257 | if (originalNote.metadata?.content?.external_urls?.[0]) { 258 | return ( 259 | originalNote.metadata.content.external_urls[0] + 260 | (originalNote !== note ? `#comments` : '') 261 | ) 262 | } else { 263 | const { character } = originalNote 264 | if (character) { 265 | return `${getSiteLink({ 266 | subdomain: character.handle, 267 | })}/${getNoteSlug(originalNote)}${ 268 | originalNote !== note ? `#comments` : '' 269 | }` 270 | } else { 271 | return '' 272 | } 273 | } 274 | } else { 275 | return `${CSB_IO}/notes/${note.characterId}-${note.noteId}` 276 | } 277 | }, 278 | } 279 | 280 | const wagmiClient = createClient(getDefaultClientConfig({ appName: 'xLog' })) 281 | const queryClient = new QueryClient({ 282 | defaultOptions: { 283 | queries: { 284 | cacheTime: 1000 * 60 * 60 * 24, // 24 hours 285 | }, 286 | }, 287 | }) 288 | const App = forwardRef((props, ref) => { 289 | return React.createElement( 290 | WagmiConfig, 291 | { client: wagmiClient }, 292 | React.createElement( 293 | QueryClientProvider, 294 | { client: queryClient }, 295 | React.createElement( 296 | ConnectKitProvider, 297 | { ipfsLinkToHttpLink: toGateway, urlComposer }, 298 | React.createElement(Instance, { ref }), 299 | props.children, 300 | ), 301 | ), 302 | ) 303 | }) 304 | const Instance = forwardRef((props, ref) => { 305 | const model = useConnectModal() 306 | const poster = useCreateOrUpdatePage() 307 | useImperativeHandle(ref, () => { 308 | return { 309 | show() { 310 | model.show() 311 | }, 312 | connectModal: model, 313 | createOrUpdatePage: (...rest) => { 314 | return poster.call(null, ...rest) 315 | }, 316 | } 317 | }) 318 | // TODO GC 319 | // useEffect(() => {}, []) 320 | return null 321 | }) 322 | 323 | export { 324 | App, 325 | IPFS_GATEWAY, 326 | IPFS_PREFIX, 327 | createOrUpdatePage, 328 | getLocalPages, 329 | getPage, 330 | useCreateOrUpdatePage, 331 | useUnidata, 332 | } 333 | // # sourceMappingURL=index.js.map 334 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-react-wrapper", 3 | "version": "0.3.1", 4 | "description": "A wrapper of React, use React in Vue with data reactive", 5 | "author": "Innei", 6 | "license": "MIT", 7 | "main": "dist/index.cjs.js", 8 | "module": "dist/index.esm.js", 9 | "types": "dist/index.d.ts", 10 | "unpkg": "dist/index.umd.min.js", 11 | "exports": { 12 | ".": { 13 | "import": "./dist/index.esm.js", 14 | "require": "./dist/index.cjs.js", 15 | "types": "./dist/index.d.ts" 16 | }, 17 | "./react": { 18 | "import": "./esm/libs/react.js", 19 | "require": "./lib/libs/react.js", 20 | "types": "./esm/libs/react.d.ts" 21 | }, 22 | "./react-dom": { 23 | "import": "./esm/libs/react-dom.js", 24 | "require": "./lib/libs/react-dom.js", 25 | "types": "./esm/libs/react-dom.d.ts" 26 | } 27 | }, 28 | "files": [ 29 | "src", 30 | "dist", 31 | "lib", 32 | "esm", 33 | "readme.md", 34 | "tsconfig.json" 35 | ], 36 | "engines": { 37 | "pnpm": ">=7" 38 | }, 39 | "husky": { 40 | "hooks": { 41 | "pre-commit": "lint-staged" 42 | } 43 | }, 44 | "lint-staged": { 45 | "*.{js,jsx,ts,tsx}": [ 46 | "prettier --ignore-path ./.prettierignore --write ", 47 | "eslint --cache" 48 | ] 49 | }, 50 | "scripts": { 51 | "prepare": "husky install", 52 | "predeploy": "rm -rf example/dist", 53 | "prebuild": "rm -rf rm -rf lib && rm -rf esm", 54 | "build": "ttsc --build src/tsconfig.build.json && ttsc --build src/tsconfig.cjs.json", 55 | "package": "NODE_ENV=production npm run build && rollup -c", 56 | "postpackage": "dts-bundle-generator -o dist/index.d.ts src/index.ts --project tsconfig.json --no-check", 57 | "prepackage": "rm -rf build", 58 | "dev": "vite", 59 | "build:vite": "vite build", 60 | "preview": "vite preview --port 2323", 61 | "deploy": "vite build && gh-pages -d example/dist", 62 | "test": "vitest " 63 | }, 64 | "bump": { 65 | "before": [ 66 | "npm run package" 67 | ], 68 | "publish": true 69 | }, 70 | "peerDependencies": { 71 | "vue": "^3" 72 | }, 73 | "devDependencies": { 74 | "@crossbell/connect-kit": "0.0.55", 75 | "@crossbell/contract": "0.0.55", 76 | "@innei-util/eslint-config-react-ts": "0.8.2", 77 | "@innei-util/eslint-config-ts": "latest", 78 | "@innei-util/prettier": "latest", 79 | "@rollup/plugin-commonjs": "22.0.0", 80 | "@rollup/plugin-node-resolve": "13.3.0", 81 | "@rollup/plugin-typescript": "8.3.2", 82 | "@tanstack/react-query": "4.28.0", 83 | "@types/node": "17.0.31", 84 | "@types/react-beautiful-dnd": "13.1.2", 85 | "@unocss/preset-wind": "0.33.2", 86 | "@vitejs/plugin-vue": "2.3.2", 87 | "@zerollup/ts-transform-paths": "1.7.18", 88 | "dts-bundle-generator": "6.9.0", 89 | "gh-pages": "3.2.3", 90 | "husky": "8.0.1", 91 | "lint-staged": "12.4.1", 92 | "naive-ui": "2.28.4", 93 | "prettier": "2.6.2", 94 | "react-beautiful-dnd": "13.1.0", 95 | "react-json-view": "1.21.3", 96 | "react-markdown": "8.0.3", 97 | "rollup": "2.72.1", 98 | "rollup-plugin-peer-deps-external": "2.2.4", 99 | "rollup-plugin-terser": "7.0.2", 100 | "tslib": "2.4.0", 101 | "ttypescript": "1.5.13", 102 | "typescript": "4.6.4", 103 | "unocss": "0.33.2", 104 | "vite": "2.9.8", 105 | "vite-tsconfig-paths": "3.4.1", 106 | "vitest": "0.12.1", 107 | "vue": "3.2.33", 108 | "unidata.js": "0.7.17", 109 | "kbar": "0.1.0-beta.34", 110 | "wagmi": "0.12.8" 111 | }, 112 | "dependencies": { 113 | "@types/prop-types": "*", 114 | "@types/react": "./src/react-types/react", 115 | "@types/react-dom": "18.0.3", 116 | "@types/scheduler": "*", 117 | "csstype": "^3.0.2", 118 | "react": "^18.1.0", 119 | "react-dom": "^18.1.0" 120 | }, 121 | "resolutions": { 122 | "@types/react": "./src/react-types/react" 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Vue React Wrapper 2 | 3 | Status: Alpha 4 | 5 | A wrapper of react component, use react component in vue quickly. 6 | 7 | ## Why 8 | 9 | As we all know, Vue 3 is becoming more and more popular, not only for its light weight, but also for its efficient performance. However, Vue's ecology has always been lacking, and in some cases, there is no substitute for the same React component. 10 | 11 | I just wanted to find a JSONViewer for Vue 3, but there wasn't one, but the React ecosystem blossomed. 12 | 13 | So, is there a way to use React in Vue? Only in a certain scenario, because the whole business uses Vue and only a few scenarios need React support, so it is not a big problem to mix the two frameworks. In the decimal scenario, createReactWrapper can be dynamically imported to reduce the first loading bundle size of the entire App. 14 | 15 | ## Install 16 | 17 | ``` 18 | npm i vue-react-wrapper 19 | ``` 20 | 21 | ## Requirement 22 | 23 | - Vue 3 24 | 25 | ## Setting TSConfig 26 | 27 | ```json 28 | { 29 | "compilerOptions": { 30 | "jsxImportSource": "vue" 31 | } 32 | } 33 | ``` 34 | 35 | ## Simple Usage 36 | 37 | Example for [react-json-view](https://github.com/mac-s-g/react-json-view) 38 | 39 | ```tsx 40 | import ReactJSONView from 'react-json-view' 41 | import { defineComponent, reactive } from 'vue' 42 | import { createReactWrapper } from 'vue-react-wrapper' 43 | 44 | // must pass a vue reactive object or Ref 45 | const props = reactive({ 46 | // ref type also work 47 | // props 48 | src: null as any, 49 | indentWidth: 2, 50 | theme: 'rjv-default', 51 | }) 52 | 53 | // JSONView is vue component 54 | // ReactJSONView is a React Component 55 | const JSONView = createReactWrapper(ReactJSONView, props) 56 | 57 | export default defineComponent({ 58 | setup() { 59 | return () => 60 | }, 61 | }) 62 | ``` 63 | 64 | And if you prefer write vue sfc. 65 | 66 | ```vue 67 | 70 | 71 | 89 | ``` 90 | 91 | ## Pass slot or react children 92 | 93 | Here is a simple React component. 94 | 95 | ```ts 96 | export const List = (props) => { 97 | return React.createElement('div', null, [ 98 | React.createElement( 99 | 'ul', 100 | null, 101 | props.data.map((item) => React.createElement('li', { key: item }, item)), 102 | ), 103 | 104 | props.children, 105 | ]) 106 | } 107 | ``` 108 | 109 | Pass react children like this. 110 | 111 | ```vue 112 | 119 | 120 | 135 | ``` 136 | 137 | Pass default slot just change to this. Unlike the above, this will be injected into the Vue container instead of the React Children scope. 138 | 139 | ```vue 140 | 145 | ``` 146 | 147 | ## Get react component inner ref 148 | 149 | ```vue 150 | 153 | 154 | 170 | ``` 171 | 172 | ## Access react lifecycle 173 | 174 | - pass `:onReactMount` or `@react-mount` 175 | - pass `:onReactUnMount` or `@react-unmount` 176 | 177 | ## Other usage 178 | 179 | Check `./example/App.vue` 180 | 181 | ## TODO 182 | 183 | - [x] support react forwardRef 184 | - [ ] support root react container and root context 185 | - [x] support pass vue ref 186 | - [x] react types without global jsx namespace 187 | 188 | ## Reference 189 | 190 | Other similar libraries. 191 | 192 | - For Vue 2 [vuera](https://github.com/akxcv/vuera) 193 | 194 | ## License 195 | 196 | MIT. Coding with ❤. 197 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": false, 3 | "extends": [ 4 | "config:base", 5 | ":semanticCommits", 6 | ":automergePatch", 7 | ":automergeTypes", 8 | ":automergeTesters", 9 | ":automergeLinters", 10 | ":automergeMinor", 11 | ":rebaseStalePrs" 12 | ], 13 | "packageRules": [ 14 | { 15 | "updateTypes": ["major"], 16 | "labels": ["UPDATE-MAJOR"] 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // import { babel } from '@rollup/plugin-babel' 3 | import peerDepsExternal from 'rollup-plugin-peer-deps-external' 4 | import { terser } from 'rollup-plugin-terser' 5 | 6 | import commonjs from '@rollup/plugin-commonjs' 7 | // import esbuild from 'rollup-plugin-esbuild' 8 | import { nodeResolve } from '@rollup/plugin-node-resolve' 9 | import typescript from '@rollup/plugin-typescript' 10 | 11 | const packageJson = require('./package.json') 12 | 13 | const umdName = packageJson.name 14 | 15 | const globals = { 16 | ...packageJson.dependencies, 17 | } 18 | 19 | const dir = 'dist' 20 | 21 | /** 22 | * @type {import('rollup').RollupOptions[]} 23 | */ 24 | const config = [ 25 | { 26 | input: 'src/index.ts', 27 | // ignore lib 28 | external: [...Object.keys(globals)], 29 | 30 | output: [ 31 | { 32 | file: `${dir}/index.umd.js`, 33 | format: 'umd', 34 | sourcemap: true, 35 | name: umdName, 36 | }, 37 | { 38 | file: `${dir}/index.umd.min.js`, 39 | format: 'umd', 40 | sourcemap: true, 41 | name: umdName, 42 | plugins: [terser()], 43 | }, 44 | { 45 | file: `${dir}/index.cjs.js`, 46 | format: 'cjs', 47 | sourcemap: true, 48 | }, 49 | { 50 | file: `${dir}/index.cjs.min.js`, 51 | format: 'cjs', 52 | sourcemap: true, 53 | plugins: [terser()], 54 | }, 55 | { 56 | file: `${dir}/index.esm.js`, 57 | format: 'es', 58 | sourcemap: true, 59 | }, 60 | { 61 | file: `${dir}/index.esm.min.js`, 62 | format: 'es', 63 | sourcemap: true, 64 | plugins: [terser()], 65 | }, 66 | ], 67 | plugins: [ 68 | nodeResolve(), 69 | commonjs({ include: 'node_modules/**' }), 70 | typescript({ tsconfig: './src/tsconfig.json', declaration: false }), 71 | // esbuild({ 72 | // include: /\.[jt]sx?$/, 73 | // exclude: /node_modules/, 74 | // sourceMap: false, 75 | // minify: process.env.NODE_ENV === 'production', 76 | // target: 'es2017', 77 | // jsxFactory: 'React.createElement', 78 | // jsxFragment: 'React.Fragment', 79 | // define: { 80 | // __VERSION__: '"x.y.z"', 81 | // }, 82 | // tsconfig: './src/tsconfig.json', 83 | // loaders: { 84 | // '.json': 'json', 85 | // '.js': 'jsx', 86 | // }, 87 | // }), 88 | // @ts-ignore 89 | peerDepsExternal(), 90 | // babel({}), 91 | ], 92 | 93 | treeshake: true, 94 | }, 95 | ] 96 | 97 | export default config 98 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare global {} 2 | export * from 'vite/client' 3 | export {} 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot, hydrateRoot } from 'react-dom/client' 3 | 4 | export * from './wrapper' 5 | 6 | export { React, createRoot, hydrateRoot } 7 | -------------------------------------------------------------------------------- /src/libs/react-dom.ts: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | 3 | export { 4 | createPortal, 5 | findDOMNode, 6 | flushSync, 7 | unmountComponentAtNode, 8 | } from 'react-dom' 9 | export default ReactDOM 10 | -------------------------------------------------------------------------------- /src/libs/react.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export { 4 | useCallback, 5 | useContext, 6 | useDebugValue, 7 | useDeferredValue, 8 | useEffect, 9 | useId, 10 | useImperativeHandle, 11 | useInsertionEffect, 12 | useLayoutEffect, 13 | useMemo, 14 | useReducer, 15 | useRef, 16 | useState, 17 | useSyncExternalStore, 18 | useTransition, 19 | createContext, 20 | createElement, 21 | createFactory, 22 | createRef, 23 | cloneElement, 24 | isValidElement, 25 | forwardRef, 26 | lazy, 27 | startTransition, 28 | memo, 29 | version, 30 | } from 'react' 31 | 32 | export default React 33 | -------------------------------------------------------------------------------- /src/react-types/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@types/react", 3 | "types": "./react.d.ts", 4 | "dependencies": {} 5 | } -------------------------------------------------------------------------------- /src/react-types/react/react.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React 17.0 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana 4 | // AssureSign 5 | // Microsoft 6 | // John Reilly 7 | // Benoit Benezech 8 | // Patricio Zavolinsky 9 | // Eric Anderson 10 | // Dovydas Navickas 11 | // Josh Rutherford 12 | // Guilherme Hübner 13 | // Ferdy Budhidharma 14 | // Johann Rakotoharisoa 15 | // Olivier Pascal 16 | // Martin Hochel 17 | // Frank Li 18 | // Jessica Franco 19 | // Saransh Kataria 20 | // Kanitkorn Sujautra 21 | // Sebastian Silbermann 22 | // Kyle Scully 23 | // Cong Zhang 24 | // Dimitri Mitropoulos 25 | // JongChan Choi 26 | // Victor Magalhães 27 | // Dale Tan 28 | // Priyanshu Rav 29 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 30 | // TypeScript Version: 2.8 31 | 32 | // NOTE: Users of the upcoming React 18 release should add a reference 33 | // to 'react/next' in their project. See next.d.ts's top comment 34 | // for reference and documentation on how exactly to do it. 35 | 36 | // NOTE: Users of the `experimental` builds of React should add a reference 37 | // to 'react/experimental' in their project. See experimental.d.ts's top comment 38 | // for reference and documentation on how exactly to do it. 39 | 40 | /// 41 | 42 | import * as CSS from 'csstype'; 43 | import * as PropTypes from 'prop-types'; 44 | import { Interaction as SchedulerInteraction } from 'scheduler/tracing'; 45 | 46 | type NativeAnimationEvent = AnimationEvent; 47 | type NativeClipboardEvent = ClipboardEvent; 48 | type NativeCompositionEvent = CompositionEvent; 49 | type NativeDragEvent = DragEvent; 50 | type NativeFocusEvent = FocusEvent; 51 | type NativeKeyboardEvent = KeyboardEvent; 52 | type NativeMouseEvent = MouseEvent; 53 | type NativeTouchEvent = TouchEvent; 54 | type NativePointerEvent = PointerEvent; 55 | type NativeTransitionEvent = TransitionEvent; 56 | type NativeUIEvent = UIEvent; 57 | type NativeWheelEvent = WheelEvent; 58 | type Booleanish = boolean | 'true' | 'false'; 59 | 60 | declare const UNDEFINED_VOID_ONLY: unique symbol; 61 | // Destructors are only allowed to return void. 62 | type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never }; 63 | 64 | // tslint:disable-next-line:export-just-namespace 65 | export = React; 66 | export as namespace React; 67 | 68 | declare namespace React { 69 | // 70 | // React Elements 71 | // ---------------------------------------------------------------------- 72 | 73 | type ElementType

= 74 | { 75 | [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K] ? K : never 76 | }[keyof JSX.IntrinsicElements] | 77 | ComponentType

; 78 | /** 79 | * @deprecated Please use `ElementType` 80 | */ 81 | type ReactType

= ElementType

; 82 | type ComponentType

= ComponentClass

| FunctionComponent

; 83 | 84 | type JSXElementConstructor

= 85 | | ((props: P) => ReactElement | null) 86 | | (new (props: P) => Component); 87 | 88 | interface RefObject { 89 | readonly current: T | null; 90 | } 91 | type RefCallback = { bivarianceHack(instance: T | null): void }["bivarianceHack"]; 92 | type Ref = RefCallback | RefObject | null; 93 | type LegacyRef = string | Ref; 94 | /** 95 | * Gets the instance type for a React element. The instance will be different for various component types: 96 | * 97 | * - React class components will be the class instance. So if you had `class Foo extends React.Component<{}> {}` 98 | * and used `React.ElementRef` then the type would be the instance of `Foo`. 99 | * - React stateless functional components do not have a backing instance and so `React.ElementRef` 100 | * (when `Bar` is `function Bar() {}`) will give you the `undefined` type. 101 | * - JSX intrinsics like `div` will give you their DOM instance. For `React.ElementRef<'div'>` that would be 102 | * `HTMLDivElement`. For `React.ElementRef<'input'>` that would be `HTMLInputElement`. 103 | * - React stateless functional components that forward a `ref` will give you the `ElementRef` of the forwarded 104 | * to component. 105 | * 106 | * `C` must be the type _of_ a React component so you need to use typeof as in React.ElementRef. 107 | * 108 | * @todo In Flow, this works a little different with forwarded refs and the `AbstractComponent` that 109 | * `React.forwardRef()` returns. 110 | */ 111 | type ElementRef< 112 | C extends 113 | | ForwardRefExoticComponent 114 | | { new (props: any): Component } 115 | | ((props: any, context?: any) => ReactElement | null) 116 | | keyof JSX.IntrinsicElements 117 | > = 118 | // need to check first if `ref` is a valid prop for ts@3.0 119 | // otherwise it will infer `{}` instead of `never` 120 | "ref" extends keyof ComponentPropsWithRef 121 | ? NonNullable["ref"]> extends Ref< 122 | infer Instance 123 | > 124 | ? Instance 125 | : never 126 | : never; 127 | 128 | type ComponentState = any; 129 | 130 | type Key = string | number; 131 | 132 | /** 133 | * @internal You shouldn't need to use this type since you never see these attributes 134 | * inside your component or have to validate them. 135 | */ 136 | interface Attributes { 137 | key?: Key | null | undefined; 138 | } 139 | interface RefAttributes extends Attributes { 140 | ref?: Ref | undefined; 141 | } 142 | interface ClassAttributes extends Attributes { 143 | ref?: LegacyRef | undefined; 144 | } 145 | 146 | interface ReactElement

= string | JSXElementConstructor> { 147 | type: T; 148 | props: P; 149 | key: Key | null; 150 | } 151 | 152 | interface ReactComponentElement< 153 | T extends keyof JSX.IntrinsicElements | JSXElementConstructor, 154 | P = Pick, Exclude, 'key' | 'ref'>> 155 | > extends ReactElement> { } 156 | 157 | /** 158 | * @deprecated Please use `FunctionComponentElement` 159 | */ 160 | type SFCElement

= FunctionComponentElement

; 161 | 162 | interface FunctionComponentElement

extends ReactElement> { 163 | ref?: ('ref' extends keyof P ? P extends { ref?: infer R | undefined } ? R : never : never) | undefined; 164 | } 165 | 166 | type CElement> = ComponentElement; 167 | interface ComponentElement> extends ReactElement> { 168 | ref?: LegacyRef | undefined; 169 | } 170 | 171 | type ClassicElement

= CElement>; 172 | 173 | // string fallback for custom web-components 174 | interface DOMElement

| SVGAttributes, T extends Element> extends ReactElement { 175 | ref: LegacyRef; 176 | } 177 | 178 | // ReactHTML for ReactHTMLElement 179 | interface ReactHTMLElement extends DetailedReactHTMLElement, T> { } 180 | 181 | interface DetailedReactHTMLElement

, T extends HTMLElement> extends DOMElement { 182 | type: keyof ReactHTML; 183 | } 184 | 185 | // ReactSVG for ReactSVGElement 186 | interface ReactSVGElement extends DOMElement, SVGElement> { 187 | type: keyof ReactSVG; 188 | } 189 | 190 | interface ReactPortal extends ReactElement { 191 | key: Key | null; 192 | children: ReactNode; 193 | } 194 | 195 | // 196 | // Factories 197 | // ---------------------------------------------------------------------- 198 | 199 | type Factory

= (props?: Attributes & P, ...children: ReactNode[]) => ReactElement

; 200 | 201 | /** 202 | * @deprecated Please use `FunctionComponentFactory` 203 | */ 204 | type SFCFactory

= FunctionComponentFactory

; 205 | 206 | type FunctionComponentFactory

= (props?: Attributes & P, ...children: ReactNode[]) => FunctionComponentElement

; 207 | 208 | type ComponentFactory> = 209 | (props?: ClassAttributes & P, ...children: ReactNode[]) => CElement; 210 | 211 | type CFactory> = ComponentFactory; 212 | type ClassicFactory

= CFactory>; 213 | 214 | type DOMFactory

, T extends Element> = 215 | (props?: ClassAttributes & P | null, ...children: ReactNode[]) => DOMElement; 216 | 217 | interface HTMLFactory extends DetailedHTMLFactory, T> {} 218 | 219 | interface DetailedHTMLFactory

, T extends HTMLElement> extends DOMFactory { 220 | (props?: ClassAttributes & P | null, ...children: ReactNode[]): DetailedReactHTMLElement; 221 | } 222 | 223 | interface SVGFactory extends DOMFactory, SVGElement> { 224 | (props?: ClassAttributes & SVGAttributes | null, ...children: ReactNode[]): ReactSVGElement; 225 | } 226 | 227 | // 228 | // React Nodes 229 | // http://facebook.github.io/react/docs/glossary.html 230 | // ---------------------------------------------------------------------- 231 | 232 | type ReactText = string | number; 233 | type ReactChild = ReactElement | ReactText; 234 | 235 | interface ReactNodeArray extends Array {} 236 | type ReactFragment = {} | ReactNodeArray; 237 | type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined; 238 | 239 | // 240 | // Top Level API 241 | // ---------------------------------------------------------------------- 242 | 243 | // DOM Elements 244 | function createFactory( 245 | type: keyof ReactHTML): HTMLFactory; 246 | function createFactory( 247 | type: keyof ReactSVG): SVGFactory; 248 | function createFactory

, T extends Element>( 249 | type: string): DOMFactory; 250 | 251 | // Custom components 252 | function createFactory

(type: FunctionComponent

): FunctionComponentFactory

; 253 | function createFactory

( 254 | type: ClassType, ClassicComponentClass

>): CFactory>; 255 | function createFactory, C extends ComponentClass

>( 256 | type: ClassType): CFactory; 257 | function createFactory

(type: ComponentClass

): Factory

; 258 | 259 | // DOM Elements 260 | // TODO: generalize this to everything in `keyof ReactHTML`, not just "input" 261 | function createElement( 262 | type: "input", 263 | props?: InputHTMLAttributes & ClassAttributes | null, 264 | ...children: ReactNode[]): DetailedReactHTMLElement, HTMLInputElement>; 265 | function createElement

, T extends HTMLElement>( 266 | type: keyof ReactHTML, 267 | props?: ClassAttributes & P | null, 268 | ...children: ReactNode[]): DetailedReactHTMLElement; 269 | function createElement

, T extends SVGElement>( 270 | type: keyof ReactSVG, 271 | props?: ClassAttributes & P | null, 272 | ...children: ReactNode[]): ReactSVGElement; 273 | function createElement

, T extends Element>( 274 | type: string, 275 | props?: ClassAttributes & P | null, 276 | ...children: ReactNode[]): DOMElement; 277 | 278 | // Custom components 279 | 280 | function createElement

( 281 | type: FunctionComponent

, 282 | props?: Attributes & P | null, 283 | ...children: ReactNode[]): FunctionComponentElement

; 284 | function createElement

( 285 | type: ClassType, ClassicComponentClass

>, 286 | props?: ClassAttributes> & P | null, 287 | ...children: ReactNode[]): CElement>; 288 | function createElement

, C extends ComponentClass

>( 289 | type: ClassType, 290 | props?: ClassAttributes & P | null, 291 | ...children: ReactNode[]): CElement; 292 | function createElement

( 293 | type: FunctionComponent

| ComponentClass

| string, 294 | props?: Attributes & P | null, 295 | ...children: ReactNode[]): ReactElement

; 296 | 297 | // DOM Elements 298 | // ReactHTMLElement 299 | function cloneElement

, T extends HTMLElement>( 300 | element: DetailedReactHTMLElement, 301 | props?: P, 302 | ...children: ReactNode[]): DetailedReactHTMLElement; 303 | // ReactHTMLElement, less specific 304 | function cloneElement

, T extends HTMLElement>( 305 | element: ReactHTMLElement, 306 | props?: P, 307 | ...children: ReactNode[]): ReactHTMLElement; 308 | // SVGElement 309 | function cloneElement

, T extends SVGElement>( 310 | element: ReactSVGElement, 311 | props?: P, 312 | ...children: ReactNode[]): ReactSVGElement; 313 | // DOM Element (has to be the last, because type checking stops at first overload that fits) 314 | function cloneElement

, T extends Element>( 315 | element: DOMElement, 316 | props?: DOMAttributes & P, 317 | ...children: ReactNode[]): DOMElement; 318 | 319 | // Custom components 320 | function cloneElement

( 321 | element: FunctionComponentElement

, 322 | props?: Partial

& Attributes, 323 | ...children: ReactNode[]): FunctionComponentElement

; 324 | function cloneElement>( 325 | element: CElement, 326 | props?: Partial

& ClassAttributes, 327 | ...children: ReactNode[]): CElement; 328 | function cloneElement

( 329 | element: ReactElement

, 330 | props?: Partial

& Attributes, 331 | ...children: ReactNode[]): ReactElement

; 332 | 333 | // Context via RenderProps 334 | interface ProviderProps { 335 | value: T; 336 | children?: ReactNode | undefined; 337 | } 338 | 339 | interface ConsumerProps { 340 | children: (value: T) => ReactNode; 341 | } 342 | 343 | // TODO: similar to how Fragment is actually a symbol, the values returned from createContext, 344 | // forwardRef and memo are actually objects that are treated specially by the renderer; see: 345 | // https://github.com/facebook/react/blob/v16.6.0/packages/react/src/ReactContext.js#L35-L48 346 | // https://github.com/facebook/react/blob/v16.6.0/packages/react/src/forwardRef.js#L42-L45 347 | // https://github.com/facebook/react/blob/v16.6.0/packages/react/src/memo.js#L27-L31 348 | // However, we have no way of telling the JSX parser that it's a JSX element type or its props other than 349 | // by pretending to be a normal component. 350 | // 351 | // We don't just use ComponentType or SFC types because you are not supposed to attach statics to this 352 | // object, but rather to the original function. 353 | interface ExoticComponent

{ 354 | /** 355 | * **NOTE**: Exotic components are not callable. 356 | */ 357 | (props: P): (ReactElement|null); 358 | readonly $$typeof: symbol; 359 | } 360 | 361 | interface NamedExoticComponent

extends ExoticComponent

{ 362 | displayName?: string | undefined; 363 | } 364 | 365 | interface ProviderExoticComponent

extends ExoticComponent

{ 366 | propTypes?: WeakValidationMap

| undefined; 367 | } 368 | 369 | type ContextType> = C extends Context ? T : never; 370 | 371 | // NOTE: only the Context object itself can get a displayName 372 | // https://github.com/facebook/react-devtools/blob/e0b854e4c/backend/attachRendererFiber.js#L310-L325 373 | type Provider = ProviderExoticComponent>; 374 | type Consumer = ExoticComponent>; 375 | interface Context { 376 | Provider: Provider; 377 | Consumer: Consumer; 378 | displayName?: string | undefined; 379 | } 380 | function createContext( 381 | // If you thought this should be optional, see 382 | // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24509#issuecomment-382213106 383 | defaultValue: T, 384 | ): Context; 385 | 386 | function isValidElement

(object: {} | null | undefined): object is ReactElement

; 387 | 388 | const Children: ReactChildren; 389 | const Fragment: ExoticComponent<{ children?: ReactNode | undefined }>; 390 | const StrictMode: ExoticComponent<{ children?: ReactNode | undefined }>; 391 | 392 | interface SuspenseProps { 393 | children?: ReactNode | undefined; 394 | 395 | /** A fallback react tree to show when a Suspense child (like React.lazy) suspends */ 396 | fallback: NonNullable|null; 397 | } 398 | /** 399 | * This feature is not yet available for server-side rendering. 400 | * Suspense support will be added in a later release. 401 | */ 402 | const Suspense: ExoticComponent; 403 | const version: string; 404 | 405 | /** 406 | * {@link https://reactjs.org/docs/profiler.html#onrender-callback Profiler API} 407 | */ 408 | type ProfilerOnRenderCallback = ( 409 | id: string, 410 | phase: "mount" | "update", 411 | actualDuration: number, 412 | baseDuration: number, 413 | startTime: number, 414 | commitTime: number, 415 | interactions: Set, 416 | ) => void; 417 | interface ProfilerProps { 418 | children?: ReactNode | undefined; 419 | id: string; 420 | onRender: ProfilerOnRenderCallback; 421 | } 422 | 423 | const Profiler: ExoticComponent; 424 | 425 | // 426 | // Component API 427 | // ---------------------------------------------------------------------- 428 | 429 | type ReactInstance = Component | Element; 430 | 431 | // Base component for plain JS classes 432 | interface Component

extends ComponentLifecycle { } 433 | class Component { 434 | // tslint won't let me format the sample code in a way that vscode likes it :( 435 | /** 436 | * If set, `this.context` will be set at runtime to the current value of the given Context. 437 | * 438 | * Usage: 439 | * 440 | * ```ts 441 | * type MyContext = number 442 | * const Ctx = React.createContext(0) 443 | * 444 | * class Foo extends React.Component { 445 | * static contextType = Ctx 446 | * context!: React.ContextType 447 | * render () { 448 | * return <>My context's value: {this.context}; 449 | * } 450 | * } 451 | * ``` 452 | * 453 | * @see https://reactjs.org/docs/context.html#classcontexttype 454 | */ 455 | static contextType?: Context | undefined; 456 | 457 | /** 458 | * If using the new style context, re-declare this in your class to be the 459 | * `React.ContextType` of your `static contextType`. 460 | * Should be used with type annotation or static contextType. 461 | * 462 | * ```ts 463 | * static contextType = MyContext 464 | * // For TS pre-3.7: 465 | * context!: React.ContextType 466 | * // For TS 3.7 and above: 467 | * declare context: React.ContextType 468 | * ``` 469 | * 470 | * @see https://reactjs.org/docs/context.html 471 | */ 472 | // TODO (TypeScript 3.0): unknown 473 | context: any; 474 | 475 | constructor(props: Readonly

| P); 476 | /** 477 | * @deprecated 478 | * @see https://reactjs.org/docs/legacy-context.html 479 | */ 480 | constructor(props: P, context: any); 481 | 482 | // We MUST keep setState() as a unified signature because it allows proper checking of the method return type. 483 | // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257 484 | // Also, the ` | S` allows intellisense to not be dumbisense 485 | setState( 486 | state: ((prevState: Readonly, props: Readonly

) => (Pick | S | null)) | (Pick | S | null), 487 | callback?: () => void 488 | ): void; 489 | 490 | forceUpdate(callback?: () => void): void; 491 | render(): ReactNode; 492 | 493 | // React.Props is now deprecated, which means that the `children` 494 | // property is not available on `P` by default, even though you can 495 | // always pass children as variadic arguments to `createElement`. 496 | // In the future, if we can define its call signature conditionally 497 | // on the existence of `children` in `P`, then we should remove this. 498 | readonly props: Readonly

& Readonly<{ children?: ReactNode | undefined }>; 499 | state: Readonly; 500 | /** 501 | * @deprecated 502 | * https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs 503 | */ 504 | refs: { 505 | [key: string]: ReactInstance 506 | }; 507 | } 508 | 509 | class PureComponent

extends Component { } 510 | 511 | interface ClassicComponent

extends Component { 512 | replaceState(nextState: S, callback?: () => void): void; 513 | isMounted(): boolean; 514 | getInitialState?(): S; 515 | } 516 | 517 | interface ChildContextProvider { 518 | getChildContext(): CC; 519 | } 520 | 521 | // 522 | // Class Interfaces 523 | // ---------------------------------------------------------------------- 524 | 525 | /** 526 | * @deprecated as of recent React versions, function components can no 527 | * longer be considered 'stateless'. Please use `FunctionComponent` instead. 528 | * 529 | * @see [React Hooks](https://reactjs.org/docs/hooks-intro.html) 530 | */ 531 | type SFC

= FunctionComponent

; 532 | 533 | /** 534 | * @deprecated as of recent React versions, function components can no 535 | * longer be considered 'stateless'. Please use `FunctionComponent` instead. 536 | * 537 | * @see [React Hooks](https://reactjs.org/docs/hooks-intro.html) 538 | */ 539 | type StatelessComponent

= FunctionComponent

; 540 | 541 | type FC

= FunctionComponent

; 542 | 543 | interface FunctionComponent

{ 544 | (props: PropsWithChildren

, context?: any): ReactElement | null; 545 | propTypes?: WeakValidationMap

| undefined; 546 | contextTypes?: ValidationMap | undefined; 547 | defaultProps?: Partial

| undefined; 548 | displayName?: string | undefined; 549 | } 550 | 551 | type VFC

= VoidFunctionComponent

; 552 | 553 | interface VoidFunctionComponent

{ 554 | (props: P, context?: any): ReactElement | null; 555 | propTypes?: WeakValidationMap

| undefined; 556 | contextTypes?: ValidationMap | undefined; 557 | defaultProps?: Partial

| undefined; 558 | displayName?: string | undefined; 559 | } 560 | 561 | type ForwardedRef = ((instance: T | null) => void) | MutableRefObject | null; 562 | 563 | interface ForwardRefRenderFunction { 564 | (props: PropsWithChildren

, ref: ForwardedRef): ReactElement | null; 565 | displayName?: string | undefined; 566 | // explicit rejected with `never` required due to 567 | // https://github.com/microsoft/TypeScript/issues/36826 568 | /** 569 | * defaultProps are not supported on render functions 570 | */ 571 | defaultProps?: never | undefined; 572 | /** 573 | * propTypes are not supported on render functions 574 | */ 575 | propTypes?: never | undefined; 576 | } 577 | 578 | /** 579 | * @deprecated Use ForwardRefRenderFunction. forwardRef doesn't accept a 580 | * "real" component. 581 | */ 582 | interface RefForwardingComponent extends ForwardRefRenderFunction {} 583 | 584 | interface ComponentClass

extends StaticLifecycle { 585 | new (props: P, context?: any): Component; 586 | propTypes?: WeakValidationMap

| undefined; 587 | contextType?: Context | undefined; 588 | contextTypes?: ValidationMap | undefined; 589 | childContextTypes?: ValidationMap | undefined; 590 | defaultProps?: Partial

| undefined; 591 | displayName?: string | undefined; 592 | } 593 | 594 | interface ClassicComponentClass

extends ComponentClass

{ 595 | new (props: P, context?: any): ClassicComponent; 596 | getDefaultProps?(): P; 597 | } 598 | 599 | /** 600 | * We use an intersection type to infer multiple type parameters from 601 | * a single argument, which is useful for many top-level API defs. 602 | * See https://github.com/Microsoft/TypeScript/issues/7234 for more info. 603 | */ 604 | type ClassType, C extends ComponentClass

> = 605 | C & 606 | (new (props: P, context?: any) => T); 607 | 608 | // 609 | // Component Specs and Lifecycle 610 | // ---------------------------------------------------------------------- 611 | 612 | // This should actually be something like `Lifecycle | DeprecatedLifecycle`, 613 | // as React will _not_ call the deprecated lifecycle methods if any of the new lifecycle 614 | // methods are present. 615 | interface ComponentLifecycle extends NewLifecycle, DeprecatedLifecycle { 616 | /** 617 | * Called immediately after a component is mounted. Setting state here will trigger re-rendering. 618 | */ 619 | componentDidMount?(): void; 620 | /** 621 | * Called to determine whether the change in props and state should trigger a re-render. 622 | * 623 | * `Component` always returns true. 624 | * `PureComponent` implements a shallow comparison on props and state and returns true if any 625 | * props or states have changed. 626 | * 627 | * If false is returned, `Component#render`, `componentWillUpdate` 628 | * and `componentDidUpdate` will not be called. 629 | */ 630 | shouldComponentUpdate?(nextProps: Readonly

, nextState: Readonly, nextContext: any): boolean; 631 | /** 632 | * Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as 633 | * cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`. 634 | */ 635 | componentWillUnmount?(): void; 636 | /** 637 | * Catches exceptions generated in descendant components. Unhandled exceptions will cause 638 | * the entire component tree to unmount. 639 | */ 640 | componentDidCatch?(error: Error, errorInfo: ErrorInfo): void; 641 | } 642 | 643 | // Unfortunately, we have no way of declaring that the component constructor must implement this 644 | interface StaticLifecycle { 645 | getDerivedStateFromProps?: GetDerivedStateFromProps | undefined; 646 | getDerivedStateFromError?: GetDerivedStateFromError | undefined; 647 | } 648 | 649 | type GetDerivedStateFromProps = 650 | /** 651 | * Returns an update to a component's state based on its new props and old state. 652 | * 653 | * Note: its presence prevents any of the deprecated lifecycle methods from being invoked 654 | */ 655 | (nextProps: Readonly

, prevState: S) => Partial | null; 656 | 657 | type GetDerivedStateFromError = 658 | /** 659 | * This lifecycle is invoked after an error has been thrown by a descendant component. 660 | * It receives the error that was thrown as a parameter and should return a value to update state. 661 | * 662 | * Note: its presence prevents any of the deprecated lifecycle methods from being invoked 663 | */ 664 | (error: any) => Partial | null; 665 | 666 | // This should be "infer SS" but can't use it yet 667 | interface NewLifecycle { 668 | /** 669 | * Runs before React applies the result of `render` to the document, and 670 | * returns an object to be given to componentDidUpdate. Useful for saving 671 | * things such as scroll position before `render` causes changes to it. 672 | * 673 | * Note: the presence of getSnapshotBeforeUpdate prevents any of the deprecated 674 | * lifecycle events from running. 675 | */ 676 | getSnapshotBeforeUpdate?(prevProps: Readonly

, prevState: Readonly): SS | null; 677 | /** 678 | * Called immediately after updating occurs. Not called for the initial render. 679 | * 680 | * The snapshot is only present if getSnapshotBeforeUpdate is present and returns non-null. 681 | */ 682 | componentDidUpdate?(prevProps: Readonly

, prevState: Readonly, snapshot?: SS): void; 683 | } 684 | 685 | interface DeprecatedLifecycle { 686 | /** 687 | * Called immediately before mounting occurs, and before `Component#render`. 688 | * Avoid introducing any side-effects or subscriptions in this method. 689 | * 690 | * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps 691 | * prevents this from being invoked. 692 | * 693 | * @deprecated 16.3, use componentDidMount or the constructor instead; will stop working in React 17 694 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state 695 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path 696 | */ 697 | componentWillMount?(): void; 698 | /** 699 | * Called immediately before mounting occurs, and before `Component#render`. 700 | * Avoid introducing any side-effects or subscriptions in this method. 701 | * 702 | * This method will not stop working in React 17. 703 | * 704 | * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps 705 | * prevents this from being invoked. 706 | * 707 | * @deprecated 16.3, use componentDidMount or the constructor instead 708 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#initializing-state 709 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path 710 | */ 711 | UNSAFE_componentWillMount?(): void; 712 | /** 713 | * Called when the component may be receiving new props. 714 | * React may call this even if props have not changed, so be sure to compare new and existing 715 | * props if you only want to handle changes. 716 | * 717 | * Calling `Component#setState` generally does not trigger this method. 718 | * 719 | * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps 720 | * prevents this from being invoked. 721 | * 722 | * @deprecated 16.3, use static getDerivedStateFromProps instead; will stop working in React 17 723 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props 724 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path 725 | */ 726 | componentWillReceiveProps?(nextProps: Readonly

, nextContext: any): void; 727 | /** 728 | * Called when the component may be receiving new props. 729 | * React may call this even if props have not changed, so be sure to compare new and existing 730 | * props if you only want to handle changes. 731 | * 732 | * Calling `Component#setState` generally does not trigger this method. 733 | * 734 | * This method will not stop working in React 17. 735 | * 736 | * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps 737 | * prevents this from being invoked. 738 | * 739 | * @deprecated 16.3, use static getDerivedStateFromProps instead 740 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props 741 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path 742 | */ 743 | UNSAFE_componentWillReceiveProps?(nextProps: Readonly

, nextContext: any): void; 744 | /** 745 | * Called immediately before rendering when new props or state is received. Not called for the initial render. 746 | * 747 | * Note: You cannot call `Component#setState` here. 748 | * 749 | * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps 750 | * prevents this from being invoked. 751 | * 752 | * @deprecated 16.3, use getSnapshotBeforeUpdate instead; will stop working in React 17 753 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#reading-dom-properties-before-an-update 754 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path 755 | */ 756 | componentWillUpdate?(nextProps: Readonly

, nextState: Readonly, nextContext: any): void; 757 | /** 758 | * Called immediately before rendering when new props or state is received. Not called for the initial render. 759 | * 760 | * Note: You cannot call `Component#setState` here. 761 | * 762 | * This method will not stop working in React 17. 763 | * 764 | * Note: the presence of getSnapshotBeforeUpdate or getDerivedStateFromProps 765 | * prevents this from being invoked. 766 | * 767 | * @deprecated 16.3, use getSnapshotBeforeUpdate instead 768 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#reading-dom-properties-before-an-update 769 | * @see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path 770 | */ 771 | UNSAFE_componentWillUpdate?(nextProps: Readonly

, nextState: Readonly, nextContext: any): void; 772 | } 773 | 774 | interface Mixin extends ComponentLifecycle { 775 | mixins?: Array> | undefined; 776 | statics?: { 777 | [key: string]: any; 778 | } | undefined; 779 | 780 | displayName?: string | undefined; 781 | propTypes?: ValidationMap | undefined; 782 | contextTypes?: ValidationMap | undefined; 783 | childContextTypes?: ValidationMap | undefined; 784 | 785 | getDefaultProps?(): P; 786 | getInitialState?(): S; 787 | } 788 | 789 | interface ComponentSpec extends Mixin { 790 | render(): ReactNode; 791 | 792 | [propertyName: string]: any; 793 | } 794 | 795 | function createRef(): RefObject; 796 | 797 | // will show `ForwardRef(${Component.displayName || Component.name})` in devtools by default, 798 | // but can be given its own specific name 799 | interface ForwardRefExoticComponent

extends NamedExoticComponent

{ 800 | defaultProps?: Partial

| undefined; 801 | propTypes?: WeakValidationMap

| undefined; 802 | } 803 | 804 | function forwardRef(render: ForwardRefRenderFunction): ForwardRefExoticComponent & RefAttributes>; 805 | 806 | /** Ensures that the props do not include ref at all */ 807 | type PropsWithoutRef

= 808 | // Pick would not be sufficient for this. We'd like to avoid unnecessary mapping and need a distributive conditional to support unions. 809 | // see: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types 810 | // https://github.com/Microsoft/TypeScript/issues/28339 811 | P extends any ? ('ref' extends keyof P ? Pick> : P) : P; 812 | /** Ensures that the props do not include string ref, which cannot be forwarded */ 813 | type PropsWithRef

= 814 | // Just "P extends { ref?: infer R }" looks sufficient, but R will infer as {} if P is {}. 815 | 'ref' extends keyof P 816 | ? P extends { ref?: infer R | undefined } 817 | ? string extends R 818 | ? PropsWithoutRef

& { ref?: Exclude | undefined } 819 | : P 820 | : P 821 | : P; 822 | 823 | type PropsWithChildren

= P & { children?: ReactNode | undefined }; 824 | 825 | /** 826 | * NOTE: prefer ComponentPropsWithRef, if the ref is forwarded, 827 | * or ComponentPropsWithoutRef when refs are not supported. 828 | */ 829 | type ComponentProps> = 830 | T extends JSXElementConstructor 831 | ? P 832 | : T extends keyof JSX.IntrinsicElements 833 | ? JSX.IntrinsicElements[T] 834 | : {}; 835 | type ComponentPropsWithRef = 836 | T extends ComponentClass 837 | ? PropsWithoutRef

& RefAttributes> 838 | : PropsWithRef>; 839 | type ComponentPropsWithoutRef = 840 | PropsWithoutRef>; 841 | 842 | type ComponentRef = T extends NamedExoticComponent< 843 | ComponentPropsWithoutRef & RefAttributes 844 | > 845 | ? Method 846 | : ComponentPropsWithRef extends RefAttributes 847 | ? Method 848 | : never; 849 | 850 | // will show `Memo(${Component.displayName || Component.name})` in devtools by default, 851 | // but can be given its own specific name 852 | type MemoExoticComponent> = NamedExoticComponent> & { 853 | readonly type: T; 854 | }; 855 | 856 | function memo

( 857 | Component: SFC

, 858 | propsAreEqual?: (prevProps: Readonly>, nextProps: Readonly>) => boolean 859 | ): NamedExoticComponent

; 860 | function memo>( 861 | Component: T, 862 | propsAreEqual?: (prevProps: Readonly>, nextProps: Readonly>) => boolean 863 | ): MemoExoticComponent; 864 | 865 | type LazyExoticComponent> = ExoticComponent> & { 866 | readonly _result: T; 867 | }; 868 | 869 | function lazy>( 870 | factory: () => Promise<{ default: T }> 871 | ): LazyExoticComponent; 872 | 873 | // 874 | // React Hooks 875 | // ---------------------------------------------------------------------- 876 | 877 | // based on the code in https://github.com/facebook/react/pull/13968 878 | 879 | // Unlike the class component setState, the updates are not allowed to be partial 880 | type SetStateAction = S | ((prevState: S) => S); 881 | // this technically does accept a second argument, but it's already under a deprecation warning 882 | // and it's not even released so probably better to not define it. 883 | type Dispatch = (value: A) => void; 884 | // Since action _can_ be undefined, dispatch may be called without any parameters. 885 | type DispatchWithoutAction = () => void; 886 | // Unlike redux, the actions _can_ be anything 887 | type Reducer = (prevState: S, action: A) => S; 888 | // If useReducer accepts a reducer without action, dispatch may be called without any parameters. 889 | type ReducerWithoutAction = (prevState: S) => S; 890 | // types used to try and prevent the compiler from reducing S 891 | // to a supertype common with the second argument to useReducer() 892 | type ReducerState> = R extends Reducer ? S : never; 893 | type ReducerAction> = R extends Reducer ? A : never; 894 | // The identity check is done with the SameValue algorithm (Object.is), which is stricter than === 895 | type ReducerStateWithoutAction> = 896 | R extends ReducerWithoutAction ? S : never; 897 | // TODO (TypeScript 3.0): ReadonlyArray 898 | type DependencyList = ReadonlyArray; 899 | 900 | // NOTE: callbacks are _only_ allowed to return either void, or a destructor. 901 | type EffectCallback = () => (void | Destructor); 902 | 903 | interface MutableRefObject { 904 | current: T; 905 | } 906 | 907 | // This will technically work if you give a Consumer or Provider but it's deprecated and warns 908 | /** 909 | * Accepts a context object (the value returned from `React.createContext`) and returns the current 910 | * context value, as given by the nearest context provider for the given context. 911 | * 912 | * @version 16.8.0 913 | * @see https://reactjs.org/docs/hooks-reference.html#usecontext 914 | */ 915 | function useContext(context: Context/*, (not public API) observedBits?: number|boolean */): T; 916 | /** 917 | * Returns a stateful value, and a function to update it. 918 | * 919 | * @version 16.8.0 920 | * @see https://reactjs.org/docs/hooks-reference.html#usestate 921 | */ 922 | function useState(initialState: S | (() => S)): [S, Dispatch>]; 923 | // convenience overload when first argument is omitted 924 | /** 925 | * Returns a stateful value, and a function to update it. 926 | * 927 | * @version 16.8.0 928 | * @see https://reactjs.org/docs/hooks-reference.html#usestate 929 | */ 930 | function useState(): [S | undefined, Dispatch>]; 931 | /** 932 | * An alternative to `useState`. 933 | * 934 | * `useReducer` is usually preferable to `useState` when you have complex state logic that involves 935 | * multiple sub-values. It also lets you optimize performance for components that trigger deep 936 | * updates because you can pass `dispatch` down instead of callbacks. 937 | * 938 | * @version 16.8.0 939 | * @see https://reactjs.org/docs/hooks-reference.html#usereducer 940 | */ 941 | // overload where dispatch could accept 0 arguments. 942 | function useReducer, I>( 943 | reducer: R, 944 | initializerArg: I, 945 | initializer: (arg: I) => ReducerStateWithoutAction 946 | ): [ReducerStateWithoutAction, DispatchWithoutAction]; 947 | /** 948 | * An alternative to `useState`. 949 | * 950 | * `useReducer` is usually preferable to `useState` when you have complex state logic that involves 951 | * multiple sub-values. It also lets you optimize performance for components that trigger deep 952 | * updates because you can pass `dispatch` down instead of callbacks. 953 | * 954 | * @version 16.8.0 955 | * @see https://reactjs.org/docs/hooks-reference.html#usereducer 956 | */ 957 | // overload where dispatch could accept 0 arguments. 958 | function useReducer>( 959 | reducer: R, 960 | initializerArg: ReducerStateWithoutAction, 961 | initializer?: undefined 962 | ): [ReducerStateWithoutAction, DispatchWithoutAction]; 963 | /** 964 | * An alternative to `useState`. 965 | * 966 | * `useReducer` is usually preferable to `useState` when you have complex state logic that involves 967 | * multiple sub-values. It also lets you optimize performance for components that trigger deep 968 | * updates because you can pass `dispatch` down instead of callbacks. 969 | * 970 | * @version 16.8.0 971 | * @see https://reactjs.org/docs/hooks-reference.html#usereducer 972 | */ 973 | // overload where "I" may be a subset of ReducerState; used to provide autocompletion. 974 | // If "I" matches ReducerState exactly then the last overload will allow initializer to be omitted. 975 | // the last overload effectively behaves as if the identity function (x => x) is the initializer. 976 | function useReducer, I>( 977 | reducer: R, 978 | initializerArg: I & ReducerState, 979 | initializer: (arg: I & ReducerState) => ReducerState 980 | ): [ReducerState, Dispatch>]; 981 | /** 982 | * An alternative to `useState`. 983 | * 984 | * `useReducer` is usually preferable to `useState` when you have complex state logic that involves 985 | * multiple sub-values. It also lets you optimize performance for components that trigger deep 986 | * updates because you can pass `dispatch` down instead of callbacks. 987 | * 988 | * @version 16.8.0 989 | * @see https://reactjs.org/docs/hooks-reference.html#usereducer 990 | */ 991 | // overload for free "I"; all goes as long as initializer converts it into "ReducerState". 992 | function useReducer, I>( 993 | reducer: R, 994 | initializerArg: I, 995 | initializer: (arg: I) => ReducerState 996 | ): [ReducerState, Dispatch>]; 997 | /** 998 | * An alternative to `useState`. 999 | * 1000 | * `useReducer` is usually preferable to `useState` when you have complex state logic that involves 1001 | * multiple sub-values. It also lets you optimize performance for components that trigger deep 1002 | * updates because you can pass `dispatch` down instead of callbacks. 1003 | * 1004 | * @version 16.8.0 1005 | * @see https://reactjs.org/docs/hooks-reference.html#usereducer 1006 | */ 1007 | 1008 | // I'm not sure if I keep this 2-ary or if I make it (2,3)-ary; it's currently (2,3)-ary. 1009 | // The Flow types do have an overload for 3-ary invocation with undefined initializer. 1010 | 1011 | // NOTE: without the ReducerState indirection, TypeScript would reduce S to be the most common 1012 | // supertype between the reducer's return type and the initialState (or the initializer's return type), 1013 | // which would prevent autocompletion from ever working. 1014 | 1015 | // TODO: double-check if this weird overload logic is necessary. It is possible it's either a bug 1016 | // in older versions, or a regression in newer versions of the typescript completion service. 1017 | function useReducer>( 1018 | reducer: R, 1019 | initialState: ReducerState, 1020 | initializer?: undefined 1021 | ): [ReducerState, Dispatch>]; 1022 | /** 1023 | * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument 1024 | * (`initialValue`). The returned object will persist for the full lifetime of the component. 1025 | * 1026 | * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable 1027 | * value around similar to how you’d use instance fields in classes. 1028 | * 1029 | * @version 16.8.0 1030 | * @see https://reactjs.org/docs/hooks-reference.html#useref 1031 | */ 1032 | function useRef(initialValue: T): MutableRefObject; 1033 | // convenience overload for refs given as a ref prop as they typically start with a null value 1034 | /** 1035 | * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument 1036 | * (`initialValue`). The returned object will persist for the full lifetime of the component. 1037 | * 1038 | * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable 1039 | * value around similar to how you’d use instance fields in classes. 1040 | * 1041 | * Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type 1042 | * of the generic argument. 1043 | * 1044 | * @version 16.8.0 1045 | * @see https://reactjs.org/docs/hooks-reference.html#useref 1046 | */ 1047 | function useRef(initialValue: T|null): RefObject; 1048 | // convenience overload for potentially undefined initialValue / call with 0 arguments 1049 | // has a default to stop it from defaulting to {} instead 1050 | /** 1051 | * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument 1052 | * (`initialValue`). The returned object will persist for the full lifetime of the component. 1053 | * 1054 | * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable 1055 | * value around similar to how you’d use instance fields in classes. 1056 | * 1057 | * @version 16.8.0 1058 | * @see https://reactjs.org/docs/hooks-reference.html#useref 1059 | */ 1060 | function useRef(): MutableRefObject; 1061 | /** 1062 | * The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations. 1063 | * Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside 1064 | * `useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint. 1065 | * 1066 | * Prefer the standard `useEffect` when possible to avoid blocking visual updates. 1067 | * 1068 | * If you’re migrating code from a class component, `useLayoutEffect` fires in the same phase as 1069 | * `componentDidMount` and `componentDidUpdate`. 1070 | * 1071 | * @version 16.8.0 1072 | * @see https://reactjs.org/docs/hooks-reference.html#uselayouteffect 1073 | */ 1074 | function useLayoutEffect(effect: EffectCallback, deps?: DependencyList): void; 1075 | /** 1076 | * Accepts a function that contains imperative, possibly effectful code. 1077 | * 1078 | * @param effect Imperative function that can return a cleanup function 1079 | * @param deps If present, effect will only activate if the values in the list change. 1080 | * 1081 | * @version 16.8.0 1082 | * @see https://reactjs.org/docs/hooks-reference.html#useeffect 1083 | */ 1084 | function useEffect(effect: EffectCallback, deps?: DependencyList): void; 1085 | // NOTE: this does not accept strings, but this will have to be fixed by removing strings from type Ref 1086 | /** 1087 | * `useImperativeHandle` customizes the instance value that is exposed to parent components when using 1088 | * `ref`. As always, imperative code using refs should be avoided in most cases. 1089 | * 1090 | * `useImperativeHandle` should be used with `React.forwardRef`. 1091 | * 1092 | * @version 16.8.0 1093 | * @see https://reactjs.org/docs/hooks-reference.html#useimperativehandle 1094 | */ 1095 | function useImperativeHandle(ref: Ref|undefined, init: () => R, deps?: DependencyList): void; 1096 | // I made 'inputs' required here and in useMemo as there's no point to memoizing without the memoization key 1097 | // useCallback(X) is identical to just using X, useMemo(() => Y) is identical to just using Y. 1098 | /** 1099 | * `useCallback` will return a memoized version of the callback that only changes if one of the `inputs` 1100 | * has changed. 1101 | * 1102 | * @version 16.8.0 1103 | * @see https://reactjs.org/docs/hooks-reference.html#usecallback 1104 | */ 1105 | // TODO (TypeScript 3.0): unknown> 1106 | function useCallback any>(callback: T, deps: DependencyList): T; 1107 | /** 1108 | * `useMemo` will only recompute the memoized value when one of the `deps` has changed. 1109 | * 1110 | * Usage note: if calling `useMemo` with a referentially stable function, also give it as the input in 1111 | * the second argument. 1112 | * 1113 | * ```ts 1114 | * function expensive () { ... } 1115 | * 1116 | * function Component () { 1117 | * const expensiveResult = useMemo(expensive, [expensive]) 1118 | * return ... 1119 | * } 1120 | * ``` 1121 | * 1122 | * @version 16.8.0 1123 | * @see https://reactjs.org/docs/hooks-reference.html#usememo 1124 | */ 1125 | // allow undefined, but don't make it optional as that is very likely a mistake 1126 | function useMemo(factory: () => T, deps: DependencyList | undefined): T; 1127 | /** 1128 | * `useDebugValue` can be used to display a label for custom hooks in React DevTools. 1129 | * 1130 | * NOTE: We don’t recommend adding debug values to every custom hook. 1131 | * It’s most valuable for custom hooks that are part of shared libraries. 1132 | * 1133 | * @version 16.8.0 1134 | * @see https://reactjs.org/docs/hooks-reference.html#usedebugvalue 1135 | */ 1136 | // the name of the custom hook is itself derived from the function name at runtime: 1137 | // it's just the function name without the "use" prefix. 1138 | function useDebugValue(value: T, format?: (value: T) => any): void; 1139 | 1140 | // 1141 | // Event System 1142 | // ---------------------------------------------------------------------- 1143 | // TODO: change any to unknown when moving to TS v3 1144 | interface BaseSyntheticEvent { 1145 | nativeEvent: E; 1146 | currentTarget: C; 1147 | target: T; 1148 | bubbles: boolean; 1149 | cancelable: boolean; 1150 | defaultPrevented: boolean; 1151 | eventPhase: number; 1152 | isTrusted: boolean; 1153 | preventDefault(): void; 1154 | isDefaultPrevented(): boolean; 1155 | stopPropagation(): void; 1156 | isPropagationStopped(): boolean; 1157 | persist(): void; 1158 | timeStamp: number; 1159 | type: string; 1160 | } 1161 | 1162 | /** 1163 | * currentTarget - a reference to the element on which the event listener is registered. 1164 | * 1165 | * target - a reference to the element from which the event was originally dispatched. 1166 | * This might be a child element to the element on which the event listener is registered. 1167 | * If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11508#issuecomment-256045682 1168 | */ 1169 | interface SyntheticEvent extends BaseSyntheticEvent {} 1170 | 1171 | interface ClipboardEvent extends SyntheticEvent { 1172 | clipboardData: DataTransfer; 1173 | } 1174 | 1175 | interface CompositionEvent extends SyntheticEvent { 1176 | data: string; 1177 | } 1178 | 1179 | interface DragEvent extends MouseEvent { 1180 | dataTransfer: DataTransfer; 1181 | } 1182 | 1183 | interface PointerEvent extends MouseEvent { 1184 | pointerId: number; 1185 | pressure: number; 1186 | tangentialPressure: number; 1187 | tiltX: number; 1188 | tiltY: number; 1189 | twist: number; 1190 | width: number; 1191 | height: number; 1192 | pointerType: 'mouse' | 'pen' | 'touch'; 1193 | isPrimary: boolean; 1194 | } 1195 | 1196 | interface FocusEvent extends SyntheticEvent { 1197 | relatedTarget: EventTarget | null; 1198 | target: EventTarget & T; 1199 | } 1200 | 1201 | interface FormEvent extends SyntheticEvent { 1202 | } 1203 | 1204 | interface InvalidEvent extends SyntheticEvent { 1205 | target: EventTarget & T; 1206 | } 1207 | 1208 | interface ChangeEvent extends SyntheticEvent { 1209 | target: EventTarget & T; 1210 | } 1211 | 1212 | interface KeyboardEvent extends SyntheticEvent { 1213 | altKey: boolean; 1214 | /** @deprecated */ 1215 | charCode: number; 1216 | ctrlKey: boolean; 1217 | code: string; 1218 | /** 1219 | * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. 1220 | */ 1221 | getModifierState(key: string): boolean; 1222 | /** 1223 | * See the [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#named-key-attribute-values). for possible values 1224 | */ 1225 | key: string; 1226 | /** @deprecated */ 1227 | keyCode: number; 1228 | locale: string; 1229 | location: number; 1230 | metaKey: boolean; 1231 | repeat: boolean; 1232 | shiftKey: boolean; 1233 | /** @deprecated */ 1234 | which: number; 1235 | } 1236 | 1237 | interface MouseEvent extends UIEvent { 1238 | altKey: boolean; 1239 | button: number; 1240 | buttons: number; 1241 | clientX: number; 1242 | clientY: number; 1243 | ctrlKey: boolean; 1244 | /** 1245 | * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. 1246 | */ 1247 | getModifierState(key: string): boolean; 1248 | metaKey: boolean; 1249 | movementX: number; 1250 | movementY: number; 1251 | pageX: number; 1252 | pageY: number; 1253 | relatedTarget: EventTarget | null; 1254 | screenX: number; 1255 | screenY: number; 1256 | shiftKey: boolean; 1257 | } 1258 | 1259 | interface TouchEvent extends UIEvent { 1260 | altKey: boolean; 1261 | changedTouches: TouchList; 1262 | ctrlKey: boolean; 1263 | /** 1264 | * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method. 1265 | */ 1266 | getModifierState(key: string): boolean; 1267 | metaKey: boolean; 1268 | shiftKey: boolean; 1269 | targetTouches: TouchList; 1270 | touches: TouchList; 1271 | } 1272 | 1273 | interface UIEvent extends SyntheticEvent { 1274 | detail: number; 1275 | view: AbstractView; 1276 | } 1277 | 1278 | interface WheelEvent extends MouseEvent { 1279 | deltaMode: number; 1280 | deltaX: number; 1281 | deltaY: number; 1282 | deltaZ: number; 1283 | } 1284 | 1285 | interface AnimationEvent extends SyntheticEvent { 1286 | animationName: string; 1287 | elapsedTime: number; 1288 | pseudoElement: string; 1289 | } 1290 | 1291 | interface TransitionEvent extends SyntheticEvent { 1292 | elapsedTime: number; 1293 | propertyName: string; 1294 | pseudoElement: string; 1295 | } 1296 | 1297 | // 1298 | // Event Handler Types 1299 | // ---------------------------------------------------------------------- 1300 | 1301 | type EventHandler> = { bivarianceHack(event: E): void }["bivarianceHack"]; 1302 | 1303 | type ReactEventHandler = EventHandler>; 1304 | 1305 | type ClipboardEventHandler = EventHandler>; 1306 | type CompositionEventHandler = EventHandler>; 1307 | type DragEventHandler = EventHandler>; 1308 | type FocusEventHandler = EventHandler>; 1309 | type FormEventHandler = EventHandler>; 1310 | type ChangeEventHandler = EventHandler>; 1311 | type KeyboardEventHandler = EventHandler>; 1312 | type MouseEventHandler = EventHandler>; 1313 | type TouchEventHandler = EventHandler>; 1314 | type PointerEventHandler = EventHandler>; 1315 | type UIEventHandler = EventHandler>; 1316 | type WheelEventHandler = EventHandler>; 1317 | type AnimationEventHandler = EventHandler>; 1318 | type TransitionEventHandler = EventHandler>; 1319 | 1320 | // 1321 | // Props / DOM Attributes 1322 | // ---------------------------------------------------------------------- 1323 | 1324 | /** 1325 | * @deprecated. This was used to allow clients to pass `ref` and `key` 1326 | * to `createElement`, which is no longer necessary due to intersection 1327 | * types. If you need to declare a props object before passing it to 1328 | * `createElement` or a factory, use `ClassAttributes`: 1329 | * 1330 | * ```ts 1331 | * var b: Button | null; 1332 | * var props: ButtonProps & ClassAttributes