React rc-time-picker styling and icon - reactjs

I'm using rc-time-picker in my Next.js (react.js) project:
<CustomTimePicker
className={"add-event-time-picker"}
popupClassName={"add-event-popup-time-picker"}
value={startTime}
onChange={setStartTime}
inputIcon={TimeIcon}
format={format}
inputReadOnly
clearIcon={<></>}
/>
And I changed its css so now it looks like this:
The most important thing for me is when the popup is opened (like under the end time) I want the clock icon to remain visible. And is there also a way to make the popup appear under the input field instead of on top of it?
I've tried setting a margin top for the popup but that didn't work as the popup is still rendered on top of the input.
My CustomTimePicker is just the rc-time-picker wrapped in its own component:
import React from "react";
import TimePicker from "rc-time-picker";
const CustomTimePicker = ({
className,
popupClassName,
onChange,
value,
...rest
}) => {
return (
<TimePicker
{...rest}
className={className}
popupClassName={popupClassName || className}
value={value}
onChange={onChange}
showSecond={false}
hideDisabledOptions
minuteStep={5}
use12Hours
/>
);
};
export default React.memo(CustomTimePicker);

Related

`Popover` (as React component) with `OverlayTrigger`

I'm trying to create rich React component as popover content.
If I use example with simple const popover (https://react-bootstrap.netlify.app/components/overlays/#examples-1) everything works fine.
Problem
But custom react component fails to position itself. It appears on top left of the screen
const MyPopover = React.forwardRef((props, ref) => {
return <Popover ref={ref} placement={"bottom"}>
<Popover.Header as="h3">
<Form.Control></Form.Control>
</Popover.Header>
<Popover.Body>
<strong>Holy guacamole!</strong> Check this info.
</Popover.Body>
</Popover>
})
const PopoverChooser = ({children, container}) => {
const _refTarget = useRef(null)
return <>
<OverlayTrigger
trigger="click"
placement="bottom"
overlay={<MyPopover ref={_refTarget}/>}
target={_refTarget.current}
>
{children}
</OverlayTrigger>
</>
}
export default PopoverChooser;
As you can see, I'v tried to use ref's, but it's doesn't help.
Question
How can it link popover to target button (in image as dropdown button and in code as {children}).
Or should I position MyPopover manually (by checking button ID and assigning position.. etc.?)
Completely different approach to dig in..?
Your approach to forward the ref was right. What you actually forgot is to also inject props. According to the documentation:
The and components do not position themselves.
Instead the (or ) components, inject ref and
style props.
https://react-bootstrap.netlify.app/components/overlays/#overview
So what you need to do is to spread the props like this:
const MyPopover = React.forwardRef((props, ref) => {
return (
<Popover ref={ref} {...props}>
https://codesandbox.io/s/trusting-sid-0050g9

Modal does not hide FullCalendar elements

I'm using FullCalendar in React and need a modal to pop-up when a button is clicked.
The issue I'm experiencing is that certain elements of the calendar do not fade behind the overlay and are instead at full opacity and in front of the modal.
Specifically, in dayGridMonth view the elements are the internal grid that makes up the calendar, the date numbers in each cell, the events and the current day highlight (i.e. all internal calendar elements). However, the toolbar header, the day text and the external border are all hidden as desired.
When in listDay or listWeek views, only the active button in the toolbar is misbehaving.
I've tried implementing a plain JS modal and also using react-modal. The issue persists in both.
import { useState } from "react";
import TaskModal from './TaskModal';
function Calendar (props) {
const [modalOpen, setModalOpen] = useState(false);
function addEvent () {
setModalOpen(true);
}
return (
<div>
<FullCalendar
headerToolbar={{
start: "addEvent",
center: "foo",
end: "bar",
}}
customButtons={{
addEvent: {
text: "+",
click: addEvent,
}
}}
some other props...
>
<TaskModal modalOpen={modalOpen} setModalOpen={setModalOpen} />
</div>
);
}
import Modal from "react-modal";
export default function TaskModal (props) {
Modal.setAppElement("#root");
return (
<Modal
isOpen={props.taskModalVisible}
onRequestClose={false}
contentLabel="My dialog"
>
<div>My modal dialog.</div>
<button onClick={() => props.setTaskModalVisible(false)}>Close modal</button>
</Modal>
);
}
The issue was simply that the problematic elements had a very high CSS z-index (as high as 999). This was resolved by adding className and overlayClassName props to the Modal. Then giving these classes an even higher z-index so that everything else would be behind.

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;

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;

How to change checkbox color and other styling for react-instantsearch?

I have ToggleRefinement checkboxes in my project and was trying to style it using ".ais-ToggleRefinement-checkbox {}" but the only thing that seems to be able to change is the font-size to make the checkbox bigger. Color and background-color doesn't do anything. I'd like to change the colors (especially the color when the checkbox is checked) and possibly other styling of the checkbox since I'm using BlueprintJS custom checkboxes in other parts of my website and I'd like the styling to be consistent between them.
Is there any way to achieve this?
To use the BlueprintJS components, you can use a connector. The docs for that are here and a guide for connectors in general here. This would look slightly like this:
import React from "react";
import { Checkbox } from "#blueprintjs/core";
import { connectToggleRefinement } from "react-instantsearch/connectors";
const Toggle = ({ refine, currentRefinement, label }) => (
<Checkbox
checked={currentRefinement}
label={label}
onChange={() => refine(!currentRefinement)}
/>
);
const ToggleRefinement = connectToggleRefinement(Toggle);
const App = () => (
<InstantSearch>
{/* add the rest of the app */}
<ToggleRefinement
attribute="materials"
value="Made with solid pine"
label="Solid Pine"
/>
</InstantSearch>
);

Resources