Using onPaste with react-select - reactjs

I'm trying to get onPaste working with react-select. It seems like, that it is not possible to make use of the event.
Basically I'm just doing this within the <Select/>: onPaste={(e) => this.doPasteMagic(e)}
But it is never fired. Am I missing something or is there another way to distinguish between typing and pasting?
I've seen a few suggestions about using onChange, but this seems dirty to me as well.

I was fiddling a lot with that. I find it rather surprising that this is not one of the main features of react-select. Anyway, I've found a workaround for this:
<div style={{height: '100%', width: '100%' }} onPaste={(e) => console.log(e)}>
<Select .../>
</div>
This seems to do the trick and triggers the right event at the right time.

You can create a custom input field and attach an onPaste event handler to it.
import { components } from 'react-select'
const CustomInput = props => (
<components.Input
{...props}
onPaste={myOnPasteHandler} />
)
Then pass this to Select via the 'components' prop:
import Select from 'react-select'
import CustomInput from './CustomInput'
const MySelectComponent = props => (
<Select
// ...
components={{ Input: CustomInput }} />
)

Related

Material-UI Dialog(/Modal) by clicking TextField loses focus on every onChange

<List key={"test1"} style={{ marginBottom: '10px' }}>
<TextField
required
id="filled-basic"
key={categoryData.title}
label="Title"
name="title"
value={categoryData.title}
type="name"
variant="filled"
style={{ width: "130ch" }}
onChange={(e)=>{
setCategoryData({...categoryData,
title:e.target.value})
console.log(e.target.value);
}}
/>
</List>
Material-UI Dialog(/Modal) by clicking TextField loses focus on every onChange
https://drive.google.com/file/d/17vYYnOQQNFpaki0zi-emvghAbOImykZt/view?usp=sharing
I was facing the same issue, The problem was, I was defining a component inside of another component.
You can define functions inside of functions. And since my components are just functions, it makes since that you should be able to define one function component inside another function component.
But it won’t work.
You can define a component-like function inside of another component, like this:
const renderHeader = (x) => { return <div>{x}</div> }
renderHeader is simply a function that returns some JSX. It is not, strictly speaking, a react component. You can totally define that dude inside another function component and it works like a charm.
But make two tiny subtle changes, like this:
const RenderHeader = (props) => { return <div>{props.x}</div> }
Now, it’s a real component. And Boom!! Now you get crazy “losing focus” behavior.
To fix this, I simply moved the the RendorHeader function to be a top-level function and that fixed it.

How to get the ref.current dom element when using react-select and react refs?

I have a group of react selects using the react-select package – https://react-select.com/home.
I have a component that wraps three react-selects – something basically like this:
import Select from "react-select"
function SelectGroup(){
const ref1 = useRef(null);
const ref2 = useRef(null);
const ref3 = useRef(null);
return (
<div>
<Select ref={ref1} />
<Select ref={ref2} />
<Select ref={ref3} />
</div>
)
}
I need to perform some checks to see what's in focus. The reason I am doing this is because the group of selects is a single component that needs to be able to allow the user to navigate in multiple ways through the keyboard. Spacebar, and enter keys should allow the user to shift the focus to the next select element. Arrow keys should allow the user to go to the next or previous select. So, focus needs to be managed somehow, and this means knowing what's currently in focus.
Normally, I would do that like this:
function isActiveElement(ref){
return ref?.current === document.activeElement
}
However, for ref.current react-select returns an object called StateManager – https://react-select.com/props#statemanager-props
So, ref.current === document.activeElement always returns false.
How, can I check to see which react-select is in focus? I was unable to find anything about this in the react-select docs. Maybe, I'm missing it? I have solved this problem others ways, but I was curious if there is a way to do it this "simpler way" I describe above, which may be the more common approach.
You can listen to the focus and the blur event to keep track of the currently focused Select:
export default function App() {
const [focus, setFocus] = useState(-1);
const onBlur = () => setFocus(-1);
return (
<div>
<div>Current focus: {focus}</div>
<Select
onFocus={() => setFocus(0)}
onBlur={onBlur}
options={colourOptions}
/>
<Select
onFocus={() => setFocus(1)}
onBlur={onBlur}
options={colourOptions}
/>
<Select
onFocus={() => setFocus(2)}
onBlur={onBlur}
options={colourOptions}
/>
</div>
);
};
Live Demo

In react select how to allow user to select text of selected option to copy its text

React select does not allow text selection of selected option. I want user to be able to select text of selected option. Whenever user tries to select the text of selected option, react select's menu gets open(pops up).
link for code sandbox:
https://codesandbox.io/s/bzdhr?module=/example.js
Any help appreciated, Thanks in advance.
react-select doesn't allow us to select the text.. neither in options or the selected value for that matter..
the input component dominated the div that keeps the value.. there is no way to select that div.
however.. i managed to find a work-around for you.. this should do..
https://codesandbox.io/s/react-codesandboxer-example-5jhzf
This happens because of the react-select onMouseDown event.
You can better handle it by overriding react-select custom renderers, wrap the single value renderer in a div which doesn't propagate onMouseDown events.
import React from 'react';
import Select, { Props, components, SingleValueProps } from 'react-select';
const SingleValueRenderer: React.FC<SingleValueProps<any>> = ({ children, ...props }) => (
<div
onMouseDown={(event) => {
event.stopPropagation();
}}>
<components.SingleValue {...props}>{children}</components.SingleValue>
</div>
);
const Dropdown: React.FC<Props> = (props) => (
<Select
components={{ SingleValue: SingleValueRenderer }}
{...props}
/>
);
export default Dropdown;

react-final-form with multiple select

I'm trying to build a form with a multiple value Select component by Material-UI using react-final-form. Somehow with single Select, I can get the value but with multiple, it doesn't. Somehow it seems like react-final-form is holding its own value internally.
Here's a the guiding link from Material-UI for building multiple Select:
https://codesandbox.io/s/sr6pf
I tried to replicate the very first example (without using react hook) in my form and I still miss something ?
https://codesandbox.io/embed/react-final-form-material-ui-example-jfmoe
What should I add to my Component to make this work ?
Thanks,
For some reasons I've managed to figure out the solution for my own question. The proper answer is to create a custom MultiSelect component instead of reusing the one from final-form-material-ui.
Notes: I've tried to use <Select /> from final-form-material-ui but adding multiple prop to the component will not be passed to , this is weird.
So, my custom component would look like this, almost similar to the one from their github with multiple prop added.
import React from 'react';
import FormControl from '#material-ui/core/FormControl';
import FormHelperText from '#material-ui/core/FormHelperText';
import InputLabel from '#material-ui/core/InputLabel';
import Select from '#material-ui/core/Select';
function SelectMulti({
input: { name, value, onChange, ...restInput },
meta,
label,
formControlProps,
...rest
}) {
const showError =
((meta.submitError && !meta.dirtySinceLastSubmit) || meta.error) &&
meta.touched;
return (
<FormControl {...formControlProps} error={showError}>
<InputLabel htmlFor={name} shrink>
{label}
</InputLabel>
<Select
{...rest}
multiple
name={name}
value={value}
onChange={onChange}
inputProps={restInput}
/>
{showError && (
<FormHelperText>{meta.error || meta.submitError}</FormHelperText>
)}
</FormControl>
);
}
SelectMulti.propTypes = {};
export default SelectMulti;
Hope this help someone in the future
I was able to solve this with by setting the fomat as such
<Field
name="concepts"
component={Select}
displayEmpty={trie}
multiple={true}
value={[]}
format={value => value || []}
/>
As per https://github.com/erikras/redux-form-material-ui/issues/212#issuecomment-358376925

Material-ui's Switch component onChange handler is not firing

I've put some Switches in an app and they work fine. Then I put the Switches in another app, but they don't work when clicked.
Both apps are using the same component. Here it is working in one app:
And here's the other app, not working:
In the second app, the onChange handler doesn't seem to ever fire.
The code in both apps looks like the following:
<Switch
checked={(console.log('checked:', status === 'visible'), status === 'visible')}
onChange={(e, c) => console.log('event:', e, c)}
/>
In the first app I see the output of those console.logs, while in the second app I only see the initial console.log of the checked prop, but I never see any of the onChange prop.
I checked if any ancestor elements have click handlers, and I didn't find any that are returning false, calling stopPropagation, or calling preventDefault.
Notice in the gif that when I click, the ripple effect still works, so click handling is obviously still working.
Any ideas why onChange may not be firing?
UPDATE! I replaced the switches with regular <input type="checkbox"> elements, and it works great! See:
Looks to me like something is wrong with material-ui's <Switch> component. I have a hunch that I will investigate when I get a chance: there might be more than one React singleton in the application. I'll be back to post an update.
I think, this is a weird fix and it is working smoothly for me. So, instead of handleChange I am using handleClick. I am not using event here, instead I am passing a string which is obviously the name of the state or id in case of arrays.
<Switch
checked={this.state.active}
onClick={() => this.handleToggle('active')}
value="active"
inputProps={{ 'aria-label': 'secondary checkbox' }}
/>
handleToggle = (name: string) => {
this.setState({ active: !this.state.active });
};
I tried handleChange, but the problem still persists. I hope this will get fixed soon.
I've had the same issue with Checkbox and Switch in the WordPress admin area.
Turns out, there was global CSS rule like:
input[type="checkbox"] {
height: 1rem;
width: 1rem;
}
Clicking the upper left corner of the element works, though.
As a solution, I reset some styles in my app root.
EDIT: Nevermind, I just put my whole app into shadow DOM. There are a few gotchas, I'll list them here:
You have to provide a custom insertion point for Material-UI style elements inside the shadow DOM. In general, you have to make nothing gets put outside of you shadow DOM.
You have to load/link the font inside the shadow DOM and outside the shadow DOM (the light DOM).
Use ScopedCssBaseline instead of the global reset.
Dialogs have to have their container prop specified.
This is how I've set things up with Material-UI:
// configure-shadow-dom.js
import { create } from 'jss';
import { jssPreset } from '#material-ui/core/styles';
const shadowHostId = 'my-app-root-id'
export const appRoot = document.createElement('div')
appRoot.setAttribute('id', 'app-root')
const styleInsertionPoint = document.createComment('jss-insertion-point')
export const jss = create({
...jssPreset(),
insertionPoint: styleInsertionPoint,
})
const robotoFontLink = document.createElement('link')
robotoFontLink.setAttribute('rel', 'stylesheet')
robotoFontLink.setAttribute('href', 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap')
const shadowHost = document.getElementById(shadowHostId)
shadowHost.attachShadow({ mode: 'open' })
const shadowRoot = shadowHost.shadowRoot
shadowRoot.appendChild(robotoFontLink)
shadowRoot.appendChild(styleInsertionPoint)
shadowRoot.appendChild(appRoot)
// index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import ScopedCssBaseline from '#material-ui/core/ScopedCssBaseline';
import { StylesProvider } from '#material-ui/core/styles';
import App from './App';
import { jss, appRoot } from './configure-shadow-dom';
ReactDOM.render(
<React.StrictMode>
<StylesProvider jss={jss}>
<ScopedCssBaseline>
<App />
</ScopedCssBaseline>
</StylesProvider>
</React.StrictMode>,
appRoot
);
It turns out that in my case, there was a CSS in the page, something like
.some-component { pointer-events: none; }
.some-component * { pointer-events: auto; }
where .some-component was containing my material-ui buttons and switches. I had to manually set pointer-events to all (or some value, I don't remember at at the moment) for the elements inside the switches.
So, that's one thing to look out for: check what pointer-events style is doing.
in Switch component, changing onChange to onClick worked for me:
<Switch
checked={this.state.active}
onClick={() => this.handleToggle('active')}
value="active"
inputProps={{ 'aria-label': 'secondary checkbox' }}
/>
still running into similar issues getting an event from the switch. here's a quick fix using internal state (you should be using hooks now and functional components, if not you are missing out, but you can use setState to do what i'm showing here in a class component.)
const [switchChecked, setSwitchChecked] = useState(false);
.......
<Switch checked={switchChecked} onChange={() => {setSwitchChecked(!switchChecked);}}/>
you'll need to have a value for switchChecked in the components local state.
Try this one checked or unchecked passed as a second argument.
<Switch
checked={this.state.active}
onClick={(e,flag) => this.handleToggle('active', flag)}
value="active"
inputProps={{ 'aria-label': 'secondary checkbox' }}
/>```
The issue is that you have to sniff the checked attribute from the event: event.target.checked
Full solution:
import { Switch } from '#material-ui/core';
import { useState } from 'react';
function App() {
const [checked, setChecked] = useState(false);
const switchHandler = (event) => {
//THIS IS THE SOLUTION - use event.target.checked to get value of switch
setChecked(event.target.checked);
};
return (
<div>
<Switch checked={checked} onChange={switchHandler} />
</div>
);
}
export default App;

Resources