Getting ClassList value of null when toggling mobile menu - reactjs

I'm working on building a responsive mobile navigation menu, and ran into an error with toggling open/close
The way I decided to go about it is to add className="show" that has a property of display: block to what's currently active, and className="hide" with a property of display: none.
This is my set up:
import {MenuOpen, MenuClose} from '../assets/AssetsIndex';
function menuActive() {
let menu = document.getElementById('mobile-menu');
let menuOpen = document.getElementById('menu-open');
let menuClose = document.getElementById('menu-close');
menu.classList.contains('active') ? open() : close();
function close() {
menu.classList.add('active');
menuClose.classList.add('show');
menuOpen.classList.add('hide');
menu.style.transform = 'translateX(0%)';
}
function open() {
menu.classList.remove('active');
menuOpen.classList.add('show');
menuClose.classList.add('hide');
menu.style.transform = 'translateX(100%)';
}
}
Initializing the menu icon with the class name:
<MenuOpen className='menu show' onClick={menuActive} id='menu-resting' />
<MenuClose className='menu hide' onClick={menuActive} id='menu-open' />
Scss:
.menu {
cursor: pointer;
margin: 0 auto;
position: absolute;
right: 2%;
z-index: 100;
&:hover path {
fill: #fff;
}
path {
fill: #fff;
}
}
.show {
display: block;
}
.hide {
display: none;
}
Error:
I went about displaying the menu container in the same way, so I'm not sure why I can't do the same with an SVG element. I've tried adding the properties with JS but ran into the same issue of the property value is null.
If anyone can tell me what I'm doing wrong that would be greatly appreciated.

There is no element with id menu-close in your code. Probably a typo. Assuming id prop of the MenuClose component is the id of the underlying element you have menu-open there.
Also, I would suggest using state hook for controlling whether the Menu is open or closed.

Related

how to replace 'selected text' => 'decorated text' in react / textarea? i can't get exact location(index) of 'selected text'

i'm trying to build some text editor with react
i'm not native in english, so sorry about below question
what i want to do is like this below
(it's 'notion' page gif)
if user drag text with mouse(or with keyboard) to set a block in some texts,
popup menu(to edit 'seleted texts') show
i'm stuck at first one.
i can get whole text and selected text
let wholeText = whole.anchorNode.childNodes[0].defaultValue;
let selectedText = window.getSelection().toString();
but i can't get 'exact location' of selectedText in wholeText
here's my code (react, styled-component)
import { useState, useEffect } from 'react';
import styled from 'styled-components';
import autosize from 'autosize';
export default function TextBox({ id, index, content, handleContentInput }) {
const [currentContent, setCurrentContent] = useState(content);
const [areaHeight, setAreaHeight] = useState(25);
useEffect(() => {
autosize(document.querySelector(`.TextBoxWrap_${id}`));
}, [currentContent]);
return (
<TextBoxContainer
className={`TextBoxContainer_${id}`}
areaHeight={areaHeight}
onClick={() => {
document.querySelector(`.TextBoxContainer_${id}`).focus();
}}
>
<TextBoxWrap
className={`TextBoxWrap_${id}`}
areaHeight={areaHeight}
onChange={(event) => {
setCurrentContent(event.target.value);
}}
onBlur={() => handleContentInput(id, index, currentContent)}
onKeyUp={() => {
let newHeight = document.querySelector(`.TextBoxWrap_${id}`)
.clientHeight;
setAreaHeight(newHeight);
}}
onMouseUp={() => {
let whole = window.getSelection();
if (!whole) return;
let range = whole.getRangeAt(0);
console.log({ whole, range });
let wholeText = whole.anchorNode.childNodes[0].defaultValue;
let selectedText = whole.toString();
console.log({ wholeText, selectedText });
let start = range.startOffset; // Start position
let end = range.endOffset; // End position
console.log({ start, end });
}}
value={currentContent}
></TextBoxWrap>
</TextBoxContainer>
);
}
const TextBoxContainer = styled.div`
max-width: 890px;
width: 100%;
height: ${(props) => `${props.areaHeight}px`};
border: 1px solid black;
margin: 3px;
padding: 2px;
`;
const TextBoxWrap = styled.textarea`
/* border: 1px solid black; */
box-sizing: 'border-box';
border: none;
outline: none;
width: 100%;
min-height: 20px;
height: 20px;
/* padding: 2x; */
box-shadow: none;
display: block;
overflow: hidden; // Removes scrollbar
resize: none;
font-size: 18px;
/* line-height: 1.5em; */
/* font-family: Georgia, 'Malgun Gothic', serif; */
`;
inside of onMouseUp, it works like this
console.log({ wholeText, selectedText }); : works fine
console.log({ start, end }); : always 0, 0
wholeText.indexOf(selectedText) was my option, but indexOf() gives me just 'first' index matches,
so, even if i want "aaaaaa'a'aa" but indexOf will give me '0' (=> "'a'aaaaaaaaaa")
what i was thinking,
get the 'exact index(location)', and cut wholeText with it
decorate selectedText with popup box (return html element? like <span style{{color: 'red'}}>${selectedText}
then, combine these three items (wholeText_front, decorated_selectedText, wholeText_back)
and, to place popup menu div right above seleted texts
which means, i need 'selected one's location
how can i do this? plz give me advice
thank you!
posts i read before post this question
How to find index of selected text in getSelection() using javascript?
How to get the start and end points of selection in text area?
replace selected text in contenteditable div
Replacing selected text - HTML / JavaScript
Select Text & highlight selection or get selection value (React)
i might have some solution for my question, so post this answer myself
in this question(How to get the start and end points of selection in text area?), 'Tim Down' answered with getInputSelection function.
getInputSelection needs el as parameter, and i thought this is some kind of 'html element'
so, from this question(get id of focused element using javascript
), i got a hint : document.activeElement
and, i tried getInputSelection(document.activeElement) and got an object like { start: (number), end: (number) }

Problems with ref focus using componentDidUpdate + opacity and visibility animation in css

I'm trying to focus() an input inside a modal right after it opens using the modal's componentDidUpdate().
This is the CSS I'm using for the modal root element:
.auth-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
visibility: hidden;
opacity: 0;
transition: visibility 400ms, opacity 400ms;
&.auth-modal_is-opened {
visibility: visible;
opacity: 1;
}
}
As you can see, it has visibility: hidden; and opacity: 0; at first.
Then I have this in the modal component:
componentDidMount() {
this.emailInput.focus();
}
componentDidUpdate() {
this.emailInput.focus();
}
The componentDidMount() hook works as intended, the input gets focused, but the componentDidUpdate() hook does not work (as though it gets called, only the focus() doesn't work as intended).
I've managed to find the reason and it happens to be the CSS animation. If I remove the visibility animation it works (but the animation breaks, of course). I've also managed to make it work using a setTimeout() inside the hook as bellow:
componentDidUpdate() {
setTimeout(() => {
this.emailInput.focus();
}, 100);
}
This also works, but feels super hackish.
Is there any better way to achieve this? (I'm currently setting a timeout as a hack solution)

ng-repeat active class with different style

I am creating a list of offers with ng-repeat. Depending of each offer status, they should have different colors and, when active, it should have a different specific status as well. The active logic works well, but what is happening now, is that they all render as true, so they're all the same color. Feel free if you have any other ideas of doing this.
This is what I see when I inspect, after it renders:
ng-class="{'offer card-active-false card row text-left': currentOfferId === offer.id, 'offer card card-false row text-left': currentOfferId !== offer.id}" class="offer card card-true row text-left"
Here is what I have on HTML:
<div ng-repeat="offer in $parent.offersList track by $index">
<button ng-click="$ctrl.setCurrentOffer(offer)">
<div ng-if="" ng-class="{'offer card-active-{{offer.status}} card row text-left': currentOfferId === offer.id, 'offer card card-{{offer.status}} row text-left': currentOfferId !== offer.id}">
//then I have my divs
</div>
</button>
</div>
CCS:
.card-true {
background-color: #00FF44;
}
.card-false {
background-color: #C4C4CC;
}
.card- {
background-color: yellow;
}
.card-active-true {
background-color: #fff!important;
border-color: #00FF44;
}
.card-active-false {
background-color: #fff!important;
border-color: gray;
}
.card-active- {
background-color: #fff!important;
border-color: yellow;
}
thanks!
Put classes that always need to be present in a normal class attribute.
Then simplify the classes you need and separate them so you don't have to over-complicate the logic. My suggestions may be off, but it should look something like this:
card-status-... - driven by offer.status
card-active - driven by `currentOfferId === offer.id'
Then you could easily put the logic in ngClass, which lets you specify an array whose members can be strings that represent class names or objects whose keys are class names and whose boolean values indicate whether the class should be included. Like so:
<div class="offer card row text-left"
ng-class="[
'card-status-' + offer.status,
{'card-active' : currentOfferId === offer.id}
]">
Now in your CSS you can set up those classes by combining selectors:
.card {
background-color: yellow;
}
.card-status-true {
background-color: #00FF44;
}
.card-status-false {
background-color: #C4C4CC;
}
.card.card-active {
background-color: #fff !important;
border-color: yellow;
}
.card.card-active.card-status-true {
background-color: #fff !important;
border-color: #00FF44;
}
.card.card-active.card-status-false {
background-color: #fff !important;
border-color: gray;
}
Here is my solution, remove the complicated logic, which is obviously not binding properly inside the ng-class, it will only confuse and its not worth the time.
Note: I have used $scope variables instead of this, please use the GIST of the JSFiddle I'm sharing and try to build your code, I am unsure of the color requirements, please check and tell me if the code resolves your issue.
JSFiddle Demo
CODE:
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
$scope.offersList = [{id:1, status: false}, {id:2, status: false}, {id:3, status: false}, {id:4, status: false}];
$scope.currentOfferId = 0;
$scope.setCurrentOffer=function(index){
$scope.currentOfferId = $scope.offersList[index].id;
$scope.offersList[index].status = !$scope.offersList[index].status;
}
$scope.filterClass = function(offer){
var bool = offer.status ? 'true' : 'false';
if($scope.currentOfferId === offer.id){
return 'offer card-active-'+bool;
}else{
return 'offer card card-'+bool;
}
}
});
It's not completely clear which classes you want applied to which situation. You need to hand ng-class an array with each separate condition, this was probably the root of your problem.
You can also use ternary for this (angular v.1.1.4+ introduced support for ternary operator) which makes things look a little neater:
<div ng-class="[offer.id ===currentOfferId ? 'card-active-true' : 'card-active-false',
offer.status ? 'card-active-true' : 'card-false' ]"
class="offer card row text-left" >

How to make Extjs Button look a link?

I want to either make a link in Extjs or make a button look like a link and on hover you see the button. They do this in the docs with Code Editor button and the Live Preview button.
If they do this using CSS, what CSS do I use and when/how to I apply it?
I recently wanted a LinkButton component. I tried to find a pre-existing component without any luck, so I ended up writing one from scratch. Its implementation is almost entirely CSS-based.
/******************************************************************************/
/*** LINK BUTTON CSS **********************************************************/
/******************************************************************************/
a.ux-linkbutton {
background-image: none;
border: 0px none;
margin-top: 1px;
}
a.ux-linkbutton.x-btn-default-small-focus {
background-color: inherit;
}
a.ux-linkbutton * {
font-size: inherit !important;
}
a.ux-linkbutton:hover {
text-decoration: underline;
background-color: inherit;
}
/******************************************************************************/
/*** LINK BUTTON JS ***********************************************************/
/******************************************************************************/
Ext.define( "Ext.ux.button.LinkButton", {
extend: "Ext.button.Button",
alias: "widget.linkbutton",
cls: "ux-linkbutton",
initComponent: function() {
this.callParent();
this.on( "click", this.uxClick, this, { priority: 999 } );
},
// This function is going to be used to customize
// the behaviour of the button and click event especially as it relates to
// its behaviour as a link and as a button and how these aspects of its
// functionality can potentially conflict.
uxClick: function() {
//Ext.EventObject.preventDefault();
//Ext.EventObject.stopEvent();
//Ext.EventObject.stopPropagation();
//return false;
}
} );
The click handler is a work-in-progress.
The class does have one minor issue: a pseudo-class style is applied after clicking/focusing that I have not been able to remove. If someone fixes it before I do, please, post the CSS for it.
With Ext 4.0.7 I had managed to do the following:
View:
...
{
xtype: 'button'
,text: 'Discard changes'
,action: 'cancel'
,cls: 'secondary-action-btn'
}
CSS:
....
.secondary-action-btn {
border: none;
background: none;
}
.secondary-action-btn span {
cursor: pointer;
text-decoration: underline;
}
I recall there is an extension called linkButton. You can refer to the extjs forum here

ExtJS: setDisabled(true) makes fields too dim / transparent to read

When I set a form field into the disabled state using setDisabled or the disabled: true config, for example:
form.getComponent(1).setDisabled(true);
it makes the field unreadable due to the transparency. Is there a good way to improve the look and feel of my disabled fields?
This Worked for me:)
.x-item-disabled {
filter : '' !important;
}
A quick solution is to change the opacity setting in the ext-all.css (or ext-all-debug.css) file. The default setting seems to be:
.x-item-disabled .x-form-trigger {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=30);
opacity: 0.3; }
If you change the opacity values to 0.6 you get a readable form.
Obviously not ideal as you are changing the core framework files but I certainly didn't find a quicker way to correct this.
I did something similar to y'all..
in ExtJS
{
xtype: 'combobox',
name: 'comboTest',
store: "ComboTest",
fieldLabel: "testCombo",
queryMode: "local",
displayField: "display",
valueField: "value",
disabledCls: "disabledComboTestCls" // you are now totally overriding the disabled class as set by .x-item-disabled
}
In you CSS file
.disabledComboTestCls {
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
-moz-opacity:0.5;
-khtml-opacity: 0.5;
opacity: 0.5;
}
.disabledComboTestCls input {
font-weight: bold;
color: #888888;
}
And this works well.
We use an override on Ext.form.Field, which hides the triggers etc, and then we add a css class. We then style the component, because the disabled function of ExtJS is indeed not readable enough.
Here is example code:
var originalRender = Ext.form.Field.prototype.onRender;
Ext.override(Ext.form.Field, {
UxReadOnly: false,
UxDisplayOnly: function (displayOnly, cls) {
// If no parameter, assume true
var displayOnly = (displayOnly === false) ? false : true;
if (displayOnly) {
// If a class name is passed in, use that, otherwise use the default one.
// The classes are defined in displayOnly.html for this example
var cls = (cls) ? cls : 'x-form-display-only-field';
// Add or remove the class
this.addClass(cls);
// Set the underlying DOM element's readOnly attribute
this.setReadOnly(displayOnly);
this.editable = false;
// Get this field's xtype (ie what kind of field is it?)
var xType = this.getXType();
if (xType == 'combo' | xType == 'combobox' | xType == 'Ext.ux.Combo' | xType == 'Ext.ux.ComboSearch') {
this.addClass('x-form-display-only-combo');
this.hideTrigger = true;
this.on('expand', function (field) {
if (field.hideTrigger)
field.collapse();
});
}
else if (xType == 'datefield') {
this.addClass('x-form-display-only-datefield');
this.hideTrigger = true;
this.on('expand', function () {
if (this.hideTrigger)
this.collapse();
});
this.editable = false;
} //elseif for each component u want readonly enabled
else {
this.addClass('x-form-display-only-other');
}
// For fields that have triggers (eg date,time,dateTime),
// show/hide the trigger
if (this.trigger) {
this.trigger.setDisplayed(!displayOnly);
}
} else {
this.UxFullField(cls);
}
},
afterRender: function () {
var me = this;
me.UxDisplayOnly(me.UxReadOnly, 'x-form-display-only-field');
this.callParent(arguments);
},
UxFullField: function (cls) {
// If a class name is passed in, use that, otherwise use the default one.
// The classes are defined in displayOnly.html for this example
var cls = (cls) ? cls : 'x-form-display-only-field';
this.removeCls(cls);
// Set the underlying DOM element's readOnly attribute
this.setReadOnly(false);
this.editable = true;
// Get this field's xtype (ie what kind of field is it?)
var xType = this.getXType();
if (xType == 'combo' | xType == 'combobox' | xType == 'Ext.ux.Combo' | xType == 'Ext.ux.ComboSearch') {
this.removeCls('x-form-display-only-combo');
this.setHideTrigger(false);
}
else if (xType == 'datefield') {
this.removeCls('x-form-display-only-datefield');
this.setHideTrigger(false);
this.editable = true;
}//elseif for each component u want readonly enabled
else {
this.removeCls('x-form-display-only-other');
}
// For fields that have triggers (eg date,time,dateTime),
// show/hide the trigger
if (this.trigger) {
this.setHideTrigger(false);
}
}
});
With css you hide stuff like borders etc...
.x-form-display-only-field{}
.x-form-display-only-other input, .x-form-display-only-other select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-combo input, .x-form-display-only-combo select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-datefield input, .x-form-display-only-datefield select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-file input, .x-form-display-only-file select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-checkbox { }
.x-form-display-only-radiogroup { }
Now you can add your field the following way:
Ext.create('Ext.form.field.Text', {
name: 'example',
UxReadOnly: true
});
For you Googlers, these answers are outdated if you're on Ext 5 and up. There's now a readOnly bool. The field looks exactly the same, but the value isn't editable.
documentation

Resources