vadimdemedes / ink-text-input Goto Github PK
View Code? Open in Web Editor NEWText input component for Ink
License: MIT License
Text input component for Ink
License: MIT License
Not all applications finish when this component is not rendered, and some applications are managed in rawMode independently of ink.
Adding this prop will allow to properly use this component with this type of applications.
I found UncontrolledTextInput very useful. However, there is an inconvenient place that after UncontrolledTextInput submits the input, the value will stay in the input. This is inconvenient to use, as input in the CLI is usually cleared after submission. I made the following simple adjustments based on your program. Hopefully, you have a comfortable way to add props to the application to control whether it clears its input after submission.
export class UncontrolledTextInput extends PureComponent {
state = {
value: ''
}
setValue(value) {
this.setState({value});
}
clearValue(value){
this.props.whenSubmit && this.props.whenSubmit(value)
this.setState({
value: ''
})
}
setValue = this.setValue.bind(this);
render() {
return <TextInputWithStdin {...this.props} onSubmit={this.clearValue} value={this.state.value} onChange={this.setValue}/>;
}
}
Thank you for your work!
I've tried a few other Ink components that require a separate npm installation and they all work fine, but this one doesn't for some reason. The input component clearly gets rendered but none of my button presses are registering. My installed node version is 10.16.1.
https://gist.github.com/wickstjo/c01d7e32a263e91124d9be2bb5c5138b
The quickstart on readme.md mentioned this.handleSubmit = this.handleSubmit.bind(this);
, which is empty and will set off error.
Moreover, onChange
is handled properly while onSubmit
is not.
Maybe we need to handle ENTER
?
if(s === ENTER && this.props.onSubmit && value !== originalValue){
return this.props.onSubmit(value);
}
Ref: sindresorhus/fkill-cli#83 (comment)
I think it would be a common use case and might be implemented in this useInput.
For example, I have a text input on my screen, but I want to do something when the user presses ^D
. I don't want that d
to go into the text input.
I don't control the text input so I can't wrap useInput
... is what I want to do possible? I feel like if it's not, it should be :)
When using React Router, when ink-text-input become unmounted it throws the following error:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in TextInput (created by Test)
in ink-box (created by Box)
in Box (created by Test)
in Test (created by Start)
in ink-box (created by Box)
in Box (created by Start)
in ink-box (created by Box)
in Box (created by Fullscreen)
in Fullscreen (created by Start)
in Start (created by Context.Consumer)
```
Both are rendered, but when the code runs, there is a cursor in each one, and whatever I type shows up in both. There also doesn't seem to be any way to change focus (sorry, I'm new to Ink!).
Here's the code. There are two files, index.js
:
import React from 'react'
import { render } from 'ink'
import App from './App'
try {
render(<App />)
} catch (err) {
console.log('index.js main caught', err)
}
And App.js
, where the two TextInputs are created and used:
import React from 'react'
import { Box } from 'ink'
import TextInput from 'ink-text-input'
class NumberInput extends React.Component {
constructor(props) {
super(props)
this.state = {
entry: '',
}
this.handleChange = this.handleChange.bind(this)
}
render() {
return (
<Box>
<Box marginRight={1}>{this.props.title}</Box>
<TextInput value={this.state.entry} onChange={this.handleChange} />
</Box>
)
}
handleChange(entry) {
this.setState({ entry })
try {
const num = Number(entry)
if (!Number.isNaN(num)) {
this.props.setValue(num)
}
} catch (err) {
console.log('NumberInput.handleChange caught', err)
}
}
}
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
first: 0,
second: 0,
}
this.setFirst = this.setFirst.bind(this)
this.setSecond = this.setSecond.bind(this)
}
setFirst(val) {
this.setState({ first: val })
}
setSecond(val) {
this.setState({ second: val })
}
render() {
return (
<Box flexDirection="column">
<Box>Adder</Box>
<NumberInput
key={'first'}
setValue={this.setFirst}
title="First number:"
/>
<NumberInput
key={'second'}
setValue={this.setSecond}
title="Second number:"
/>
<Box>Sum: {this.state.first + this.state.second}</Box>
</Box>
)
}
}
export default App
I noticed that showCursor
appears to not work if a mask
is set. Seems that functionality was explicitly guarded against:
Line 53 in 6c5b29d
Just curious if there's a specific reason for hiding the cursor in this case? :)
Steps to reproduce:
Expected result:
Nothing happens when you delete from the beginning of the string
Actual result:
The text in the field is duplicated
Hi there! I'm currently building something with the TextInput
component and when I'm clearing the value the behavior becomes odd and I couldn't really figure out why.
Here's what I'm doing:
const { default: InkTextInput } = require('ink-text-input');
const Example = () => {
const [content, setContent] = useState('');
useInput((_, key) => {
if (key.return) {
setContent('');
}
});
return (
<Box>
<InkTextInput value={content} onChange={setContent} />
</Box>
);
};
The first time when I type content into it, it works great. Then when I hit return and it clears it it will first capture the first character and then prepend everything else. For example if I type in 1234
it will the first time write 1234
. The second time it will write 2341
.
ink
: 3.0.3
ink-text-input
: 4.0.0
If the placeholder
prop is set, the cursor becomes invisible, even if showCursor
is set to true
.
I'm not really sure how I would expect this to be handled, I just noticed that it is slightly confusing, because the app does not look like it is waiting for input.
Is there a particular reason you decided to make it this way? Or am I missing something?
Platform: macOS 10.15
The text field never appears to change when I type. This is my entire app so far, so I figure it's a bug in your code, but let me know if I'm doing something wrong. I am using typescript btw. I can post other files as needed
import React, { useState } from 'react';
import { Text } from 'ink';
import { UncontrolledTextInput } from 'ink-text-input';
function App() {
const [submitted, submit] = useState('');
if (submitted.length) {
return <Text>{submitted}</Text>
}
return (<>
<Text color="green">Please enter some text: </Text>
<UncontrolledTextInput placeholder="placeholder" onSubmit={submit} />
</>);
}
export default App;
I am trying to make a simple app with 2 inputs. One should run after another. But when I try to type, it types on both inputs even though I'm using focus
.
import React from 'react'
import { Box, Text } from 'ink'
import { state } from './state'
import { Input } from './Input'
const App = () => (
<Box flexDirection="column">
<Text color="#A78BFA">Compose New Post</Text>
<Input
label="Title"
onSubmit={(title) => {
state.title = title
}}
/>
<Input
label="Description"
onSubmit={(description) => {
state.description = description
}}
/>
</Box>
)
module.exports = App
export default App
import React from 'react'
import { Text } from 'ink'
import { UncontrolledTextInput } from 'ink-text-input'
interface IInput {
label: string
onSubmit: (s: string) => void
}
export const Input = ({ label, onSubmit }: IInput) => {
const [submitted, setSubmitted] = React.useState(false)
const handleSubmit = (q: string) => {
onSubmit(q)
setSubmitted(true)
}
if (submitted) return null
return (
<Text>
<Text color="#6EE7B7">❯ {label}: </Text>
<UncontrolledTextInput focus={!submitted} onSubmit={handleSubmit} />
</Text>
)
}
Checkout the main branch for a reproducable demo -> https://github.com/deadcoder0904/ink-isolated-state-bug
And the fix branch contains a potential fix -> https://github.com/deadcoder0904/ink-isolated-state-bug/tree/fix
It uses a fieldNo
variable to move focus
from 1 field to another.
import React from 'react'
import { Box, Text, useApp } from 'ink'
import { state } from './state'
import { Input } from './Input'
const App = () => {
const [fieldNo, setFieldNo] = React.useState(1)
const { exit } = useApp()
React.useEffect(() => {
if (fieldNo === 3) exit()
}, [fieldNo])
return (
<Box flexDirection="column">
<Text color="#A78BFA">Compose New Post</Text>
<Input
label="Title"
focus={fieldNo === 1}
onSubmit={(title) => {
state.title = title
setFieldNo(2)
}}
/>
<Input
focus={fieldNo === 2}
label="Description"
onSubmit={(description) => {
state.description = description
setFieldNo(3)
}}
/>
</Box>
)
}
module.exports = App
export default App
I don't think this should be needed. Is this how it's supposed to work? Because I'm unable to find any simple examples online using Multiple Text Inputs & I've searched for 2 days now.
Another thing is exit
doesn't work here as it should. Am I doing anything wrong? Should I create a new issue?
If I submit and then switch what Question is rendered the previous values input on the terminal
'use strict';
const { h, render, Component } = require('ink');
const TextInput = require('ink-text-input');
const allQuestions = ['Enter service account', 'enter service key'];
class Question extends Component {
render(props, state) {
return (<div>
{props.question}:
<TextInput value={state.value || ''} onChange={(value) => this.setState({value})} onSubmit={(val) => {
props.onSubmit(val);
// this.setState({value:''});
}} />
</div>);
}
shouldComponentUpdate() { return true; }
}
class Gandalf extends Component {
constructor(props) {
super(props);
this.state = {
question: 0,
responses: [],
};
}
render(props, state) {
const { questions } = props;
const { question, responses } = state;
if (question >= questions.length) return responses.map((val, i) => (<div>Response {i}: {val}</div>));
return (
<Question
question={questions[question]}
onSubmit={(value) => this.setState({ question: question + 1, responses: responses.concat(value) })} />
);
}
}
render(<Gandalf questions={allQuestions}/>);
If you submit and then go to the next question the value sticks on the line and even is included in the value for the next question. The two ways I got around this are either to manually blank out the value or with my new code is to continue to display the question & value, which is a better experience anyway.
The example does not work with react hooks.
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `UserInfo`.
in UserInfo (created by Layout)
in div (created by Box)
in Box (created by Layout)
in Layout
in App
The above error occurred in the <div> component:
in div (created by Box)
in Box (created by UserInfo)
in UserInfo (created by Layout)
in div (created by Box)
in Box (created by Layout)
in Layout
in App
React will try to recreate this component tree from scratch using the error boundary you provided, App.
Warning: App: Error boundaries should implement getDerivedStateFromError(). In that method, return a state update to display an error message or fallback UI.
(node:9107) UnhandledPromiseRejectionWarning: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `UserInfo`.
at invariant (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:53:15)
at createFiberFromTypeAndProps (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:1913:11)
at createFiberFromElement (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:1934:15)
at createChild (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:4008:28)
at reconcileChildrenArray (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:4259:25)
at reconcileChildFibers (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:4582:14)
at reconcileChildren (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:6385:28)
at updateHostComponent (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:6846:3)
at beginWork (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:7632:14)
at performUnitOfWork (/Users/hunter/preme-o/node_modules/react-reconciler/cjs/react-reconciler.development.js:11295:12)
(node:9107) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:9107) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
// UserInfo.js
const React = require('react');
const { useState } = require('react');
const { Box } = require('ink');
const TextInput = require('ink-text-input');
const UserInfo = () => {
const [name, setName] = useState('');
return (
<Box>
<Box marginRight={1}>Enter your query:</Box>
<TextInput value={name} onChange={() => setName(name)} />
</Box>
);
};
module.exports = UserInfo;
const React = require('react');
const { Box, render } = require('ink');
const importJsx = require('import-jsx');
const Brand = importJsx('./Brand');
const UserInfo = importJsx('./UserInfo');
const Layout = () => (
<Box>
<Brand />
<UserInfo />
</Box>
);
render(<Layout />);
const importJsx = require('import-jsx');
module.exports = importJsx('./components/Layout');
https://github.com/vadimdemedes/ink-text-input/blob/master/src/index.js#L3
https://github.com/vadimdemedes/ink-text-input/blob/master/package.json#L40
Notably, this breaks installation under yarn v2. Might make sense to add ink as a peer dependency?
Cursor movement handling to the left/right position when being already in most left/right position is wrong. Being in most left/right position and moving a cursor to the left/right position one more time hides away a cursor but is expected behaviour would be to stay a cursor in the most left/right position constantly. Also there is the following nuance: the next typing chars are printing at wrong location.
ink version: 4.4.1
ink-text-input version: 5.0.1
Let's see it in action in a little demo:
Here is a repo demonstrating this issue.
When using *
to mask a password, you're still giving away password length (which gives a lot of information to potential bad actors). A lot of command line password-entry tools either do not show any characters of show a static number of ******
. It would be nice to have this here also.
Useful when you have multiple text inputs or other components, that accept some sort of input. To prevent all components handling keypress
events, they should be unfocused using focus={false}
. Should be true
by default.
If I design keyboard shortcuts for quick access to specific inputs in my GUI, like: Ctrl+N to jump to some given text field, and one <TextInput>
currently has the focus, it will use up and display the n
letter (although key.ctrl === true
, and my other useInput
in the app will be invoked and will correctly pass the focus to where I wish, but... too late).
I would suggest an additional prop to <TextInput>
: a keyFilter
callback, which would receive the input+key (just as useInput
) and would return true if the program should absorb (swallow) that key combination, or let it go through to the regular treatment of TextInput
.
I can make a PR if someone else thinks this should exit.
Thanks
This happens in a corner case when the component is unmounted due to a key input (which makes the component doesn't render anymore) but the event emitter is already iterating the listeners.
The reason this happens is, because the events emitter create a copy of the listeners to iterate them, and the stdin.removeListener
call happens after the copy is done, therefore the handleInput
listener receives the event and tries to update the state in a unmounted component, triggering a warning/error
Currently if you paste into an empty field, only the last char is displayed. Here's the log of keypress events and output when pasting "atom":
{ sequence: 'a',
name: 'a',
ctrl: false,
meta: false,
shift: false }
{ sequence: 't',
name: 't',
ctrl: false,
meta: false,
shift: false }
{ sequence: 'o',
name: 'o',
ctrl: false,
meta: false,
shift: false }
{ sequence: 'm',
name: 'm',
ctrl: false,
meta: false,
shift: false }
m
m
m
m
Notice that output follows keypress events, so it seems that keypress events arrive all at once for each char before an update to stdout is written.
Currently batching of setState()
isn't supported in Ink, but I don't think it's related / going to help this. Maybe some queueing of keypress events should be implemented in <TextInput>
.
ink-text-input
"Usage" example is not workingError: "stdin.setRawMode is not a function"
ink-text-input
after implementing componentDidCatchDid this to address the error bounds request in previous error message
Possibly related to vadimdemedes/ink#166
Would be nice to be able to pass props to the Text component like a custom color for example.
When you use the Chinese input method, you can only input one character at a time, but in fact, I have played several characters.
Currently when scrolling, the input will get weird characters like [A
or [B
Hi, when I try to run the example in the readme, I get this error:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `SearchQuery`.
in SearchQuery
in App
The above error occurred in the <div> component:
in div (created by Box)
in Box (created by SearchQuery)
in SearchQuery
in App
React will try to recreate this component tree from scratch using the error boundary you provided, App.
Warning: App: Error boundaries should implement getDerivedStateFromError(). In that method, return a state update to display an error message or fallback UI.
(node:64515) UnhandledPromiseRejectionWarning: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `SearchQuery`.
at invariant (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:53:15)
at createFiberFromTypeAndProps (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:1913:11)
at createFiberFromElement (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:1934:15)
at createChild (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:4008:28)
at reconcileChildrenArray (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:4259:25)
at reconcileChildFibers (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:4582:14)
at reconcileChildren (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:6385:28)
at updateHostComponent (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:6846:3)
at beginWork (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:7632:14)
at performUnitOfWork (/Users/isaacs/dev/js/tap/node_modules/react-reconciler/cjs/react-reconciler.development.js:11295:12)
(node:64515) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:64515) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Using [email protected], [email protected]. Same on node 8, 10, and 12.
The docs describe the usage of UncontrolledTextInput:
<UncontrolledTextInput onSubmit={handleSubmit} />
With an optional prop initialValue
.
The prop typings are wrong. The required/expected prop instead of onSubmit
is onChange
and it does not accept initialValue
at all, instead requires a value
.
So the required syntax is:
<UncontrolledTextInput value="whatever" onChange={() => { console.log('whatever')}} />
Also Except
should be replaced with Omit
to fix:
interface UncontrolledProps extends Omit<Props, 'value' | 'onChange'> {
/**
* Initial value.
*/
initialValue?: string
}
Some apps might want to use this component to allow users to enter multi-line text. Right now this is not easily achieved as enter
is hard-coded to be the "submission key".
My question/proposal would be to add an optional prop that would define what is a submission. Something like the following:
export type Props = {
// ...
/**
* Function that determines if a key press constitutes a submission (which will result in `onSubmit` being called)
*/
readonly isSubmit?: (key: Key) => boolean;
// ...
};
function TextInput({
value: originalValue,
placeholder = '',
focus = true,
mask,
highlightPastedText = false,
showCursor = true,
onChange,
isSubmit = key => key.return,
onSubmit
}: Props) {
// ...
useInput(
(input, key) => {
// ...
if (isSubmit(key) && onSubmit) {
onSubmit(originalValue);
return;
}
// ...
);
// ...
};
This would allow for apps to support multiple-line input, defining what they consider to be the submission (e.g. 3 new lines in a row), all the while being backwards compatible.
Please let me know your thoughts and I can open a PR with the changes.
It's nothing but pain..
When rendering a new TextInput
after getting another input from another TextInput
the second input does not wait and the app will exit.
e.g.
import React from "react";
import { Box } from "ink/build";
import TextInput from "ink-text-input";
const Input1 = ({ value, onChange }) => (
<Box>
Input 1:
<TextInput value={value ?? ""} onChange={onChange} />
</Box>
);
const Input2 = ({ value, onChange }) => (
<Box>
Input 2:
<TextInput value={value ?? ""} onChange={onChange} />
</Box>
);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
input1: undefined,
input2: undefined
};
this.onFirstInput = this.onFirstInput.bind(this);
this.onSecondInput = this.onSecondInput.bind(this);
}
render() {
return !this.state.input1 ? (
<Input1 onChange={this.onFirstInput} />
) : (
<Input2 onChange={this.onSecondInput} />
);
}
onFirstInput(input1) {
this.setState({
input1
});
}
onSecondInput(input2) {
this.setState({
input2
});
}
}
This will render Input 1:
and wait for input. After pressing a key it will render Input 2:
and then exit.
Why does UncontrolledTextInput
not allow an explicit initial value? For a stateful app, this is painful. I should be able to provide both a placeholder and a value and have it display the placeholder if the value is empty/nullish.
Created a new ink app, by using the create-ink-app
tool, and installed the ink-text-input
package. But am having issues with using this component.
I'm getting the following error, whenever I try to use the TextInput
component:
ERROR Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `InputBox`.
Example component:
const React = require("react");
const { Box, Text } = require("ink");
const TextInput = require("ink-text-input");
const InputBox = ({}) => {
const [value, setValue] = React.useState("");
return (
<Box flexDirection="column">
<Box>
<Text>Value:</Text>
</Box>
<Box>
<TextInput value={value} onChange={setValue} />
</Box>
</Box>
);
};
module.exports = { InputBox };
This is helpful for users who might want to make a wrapper for a stylised TextInput.
I'm getting this error when I run the code example :(
The above error occurred in the <TextInput> component:
in TextInput (created by Context.Consumer)
in TextInputWithStdin (created by SearchQuery)
in div (created by Box)
in Box (created by SearchQuery)
in SearchQuery
in App
React will try to recreate this component tree from scratch using the error boundary you provided, App.
(node:24992) UnhandledPromiseRejectionWarning: Error: Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.
Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported
at App.isEnabled (D:\*****\node_modules\ink\build\components\App.js:48:17)
at TextInput.componentDidMount (D:\*****\node_modules\ink-text-input\build\index.js:171:5)
at commitLifeCycles (D:\******\node_modules\react-reconciler\cjs\react-reconciler.development.js:12096:22)
at commitLayoutEffects (D:\*****\node_modules\react-reconciler\cjs\react-reconciler.development.js:15342:7)
at Object.invokeGuardedCallbackImpl (D:\******\node_modules\react-reconciler\cjs\react-reconciler.development.js:11563:10)
at invokeGuardedCallback (D:\****\node_modules\react-reconciler\cjs\react-reconciler.development.js:11740:31)
at commitRootImpl (D:\******\node_modules\react-reconciler\cjs\react-reconciler.development.js:15080:9)
at unstable_runWithPriority (D:\******\node_modules\scheduler\cjs\scheduler.development.js:697:12)
at runWithPriority (D:\*****\node_modules\react-reconciler\cjs\react-reconciler.development.js:1881:10)
at commitRoot (D:\*****\node_modules\react-reconciler\cjs\react-reconciler.development.js:14920:3)
(node:24992) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:24992) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
SO: Windows 10 Pro
Terminal: PowerShell 6
Package versions:
"ink": "^2.7.1",
"ink-text-input": "^3.2.2",
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.