How to use Flatpickr in Stenciljs components? - css

Flatpickr input field is not showing up in the stencil component with proper css.
I added the flatpickr date input field in a newly created (using stencil cli) app. No other settings or configs are changed.
import { Component, h } from '#stencil/core';
import flatpickr from 'flatpickr';
#Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true,
})
export class MyComponent {
private element: HTMLInputElement;
componentDidLoad() {
flatpickr(this.element, {
});
}
render() {
return (
<div>
<input ref={el => this.element = el} type="text" id="flatpickr" />
</div>
)
}
}

I'm guessing the problem is with the styling since the code you posted looks correct.
Flatpickr appends the calendar to the body element by default and since CSS is encapsulated when ShadowDOM is enabled (shadow: true) the styles in my-component.css won't affect it.
I see three options:
1. Append to different element
You can set a different parent for the calendar (your component or any element in it)
import { Component, Element, h } from '#stencil/core';
// ...
export class MyComponent {
#Element() el: HTMLElement;
private element: HTMLInputElement;
componentDidLoad() {
flatpickr(this.element, {
appendTo: this.el,
});
}
render() {
return (
<div>
<input ref={el => this.element = el} type="text" id="flatpickr" />
</div>
)
}
}
And import the styles in the CSS (my-component.css):
#import '~flatpickr/dist/flatpickr.min.css';
2. Include the Flatpickr CSS globally.
Include the CSS in your HTML head or any global CSS file.
3. Disable ShadowDOM
Set shadow: false to allow the styles in my-component.css to affect elements outside your component and import the CSS in my-component.css (same as in Option 1.).

Related

Add styles of class of external css file to Block props to use as attributes

Is it possible to use styles of a class in an external css file ( which is added to the block.json) as props to use these as attributes in the InspectorControls Component, if so, how?
I know that I can use inline styles as attributes for the InspectorControls Component. But dont know any way to use certain parts of classes in the external css files.
My css file added to the blocks.json:
"editorScript": "file:./index.js",
"editorStyle": "file:./editor.css",
"style": "file:./style.css"
I want to use Method 2 from this wordpress docs page for my classes and then use parts of the classes as attributes.
Yes, by importing the class names from a CSS module as the options for a UI control (eg <SelectControl>) the class can be applied to the block with useBlockProps().
In the example below, I used create block to setup a simple block that renders a paragraph which the user can choose the color "theme" of. It's best to use a CSS file containing only the classes you wish to load into the UI component, eg:
theme.scss (or an external css file)
.red{
color:red;
border-color: red;
}
.blue{
color:blue;
border-color: blue;
}
Create a new SCSS file with CSS modules in block/src to import the external styles:
classes.module.scss
#import './theme.scss';
Import the same external CSS in the blocks main style so it will be compiled into style.css, eg:
style.scss (main block styles)
#import './theme.scss';
.wp-block-gutenberg-default-block{
/* all custom styles for the block */
padding: 1em;
border:2px solid;
}
Alternatively, you could enqueue the stylesheet separately via PHP or via the theme..
Add a new string attribute to store the name of the class selected from the UI/SelectControl, eg:
block.json
{
...
"attributes": {
"customClassName": {
"type": "string",
"default": ""
}
},
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
}
By naming the importing the CSS module in edit(), we can have access an Object containing all the classes from theme.scss. Before displaying in the UI, the class names are formatted as options for a <SelectControl>. The selected class name is saved to the blocks attributes and applied by useBlockProps(), eg:
edit.js
import { InspectorControls, useBlockProps } from '#wordpress/block-editor';
import { PanelBody, SelectControl } from '#wordpress/components';
import styleClasses from './classes.module.scss';
export default function Edit({ attributes, setAttributes }) {
const { customClassName } = attributes;
const myClasses = [{ label: 'none', value: '' }]; // Default option for SelectControl
// Add each classname in styleClasses to myClasses
for (const key in styleClasses) {
myClasses.push({ label: key, value: key })
}
return (
<>
<InspectorControls>
<PanelBody>
<SelectControl
label="Custom Class"
value={customClassName}
options={myClasses}
onChange={(value) => setAttributes({ customClassName: value })}
/>
</PanelBody>
</InspectorControls>
<p {...useBlockProps({ className: customClassName })}>Hello World</p>
</>
);
}
Finally, useBlockProps.save() wraps the selected classname into the blocks markup on save.
save.js
import { useBlockProps } from '#wordpress/block-editor';
export default function save({ attributes }) {
const { customClassName } = attributes;
return (
<p {...useBlockProps.save({ className: customClassName })}>Hello World</p >
);
}
End result:
Hopefully this will give you some ideas for what's possible in your own block with CSS and attributes.

Can I use react component property inside PostCss style

I'm investigating 3rd party react with PostCss component
in which I see property isOpen received from outside
import React, { Component } from 'react';
import classNames from 'classnames/bind';
import PropTypes from 'prop-types';
import styles from './Modal.css';
class Modal extends Component {
render() {
const {
isOpen,
} = this.props;
const cx = classNames.bind(styles);
const ModalClassName = cx({
Modal: true,
isOpen: isOpen,
});
return (
<div className={ModalClassName} tabIndex={0}>
... modal content ...
</div>
)
}
}
Modal.propTypes = {
isOpen: PropTypes.bool.isRequired,
};
export default Modal;
in Modal.css I can see style to hide this modal component
:local(.Modal) {
&:not(:local(.isOpen)) {
visibility: hidden;
opacity: 0;
}
}
/* ------------- I miss this one as well ------------- */
:local(.isOpen) {
#media print {
position: static !important;
}
}
Is this isOpen in CSS same variable passed to component as a property or isOpen name just a coincidence?
If yes, how come isOpen is visible within CSS? Could you please give me reference where I read about this.
After useful clarifications from #JAM let me rephrase my question.
How value in Modal property Modal.props.isOpen can trigger css style .isOpen and affect visibility of Modal component. The question is not about classnames library.
:local(.Modal) {
&:not(:local(.isOpen)) {
visibility: hidden;
opacity: 0;
}
}
How value in Modal property Modal.props.isOpen can trigger css style .isOpen and affect visibility of Modal component.
isOpen is (in simple terms) a class name imported from the css module Modal.css (from styles).
So, in your component you can then compose the classes exposed from styles as you choose, for example:
<div className={`${styles.Modal} ${styles.isOpen}`} />
The reason the .Modal is hidden when .isOpen is not part of the class name, is due to the CSS rules specified for the selector .Modal:not(.isOpen), or as specified in the css module:
:local(.Modal) {
&:not(:local(.isOpen)) {
visibility: hidden;
opacity: 0;
}
}
So, when the element has the class Modal isOpen, the element is visible. When the element has the class Modal but is missing isOpen, the element will be visibly hidden.
There is no direct correlation between the class name isOpen and te component's prop isOpen. The isOpen prop value is only used to control if the class should be set or not.
Is this isOpen in CSS same variable passed to component as a property or isOpen name just a coincidence?
I am guessing that isOpen from the component is meant to reflect the :local(.isOpen) selector in the Modal.css css module.
Based on the reading here, it seems that
this: (binding styles to classnames)
import classNames from 'classnames/bind';
import styles from './Modal.css';
const cx = classNames.bind(styles);
const ModalClassName = cx({
isOpen: true,
});
is equal to this: (referencing styles)
import classNames from 'classnames';
import styles from './Modal.css';
const ModalClassName = classNames({
[styles.isOpen]: true,
});
Because you are using css modules, the result of ModalClassName in any of the cases above will resolve into a string, to something like Modal__isOpen___hash when isOpen is true above. When isOpen is false, the result will be an empty string.
classnames is just a simple JavaScript utility for conditionally joining classNames together.
It supports binding to css module styles (by using import classnames from 'classnames/bind') as referenced in detail above.

Cant overwrite the custom stylesheet

I am trying to overwrite the CSS of react range slider.It uses the custom style sheet of which i need to add in the head section.My project is built on next.js
<link rel="stylesheet" href="https://unpkg.com/react-rangeslider/umd/rangeslider.min.css" />
Otherwise, the slider doesn't show anything if i don't add the link in head even though I installed the library. It's not even overwriting the CSS. I want to change the background color.This is my code:
import React, { Component } from 'react'
import 'react-rangeslider/lib/index.css';
import './slider.css';
import Slider from 'react-rangeslider'
class Horizontal extends Component {
constructor (props, context) {
super(props, context)
this.state = {
value: 850
}
}
handleChangeStart = () => {
console.log('Change event started')
};
handleChange = value => {
this.setState({
value: value
})
};
handleChangeComplete = () => {
console.log('Change event completed')
};
render () {
const { value } = this.state
return (
<div>
<div className='slider' style={{ marginTop:'165px',marginLeft:'319px',width:'700px',backgroundColor:'EF5350'}} >
<div style={{ textAlign:'center',color:'gray',fontSize:'35px',marginBottom:'82px'}}>
<p> What is the size of your property?</p>
</div>
<Slider
min={850}
max={5000}
value={value}
onChangeStart={this.handleChangeStart}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
<div className='value'>{value}</div>
</div>
</div>
)
}
}
export default Horizontal
I tried to change the background color in slider.css.
.rangeslider-horizontal .rangeslider__fill {
background-color: red;
}
The library needs to be installed first:
npm install react-rangeslider --save
It doesn't work as the slider stylesheet overwrite yours. Include the style like
// To include the default styles
import 'react-rangeslider/lib/index.css'
// import your css
import './style.css';
Demo
always make your own CSS stylesheet file the last file to import after any other CSS stylesheet files to make overwrite you need
otherwise, you can always use the console in the browser to auto-detect any error by pressing F12 in the browser then go to the tab called (console)
I think you can style element you want to live in the console to know the detail of how to nesting element
you also can open the CSS file in the editor and press Ctrl+F then find the line of code you want to style then copy its property and value to your own CSS file and then you can edit it so easy

Using existing css class in Stripe Elements for React

I'm trying to use our existing CSS classes in my Stripe Elements form. According to this document https://stripe.com/docs/stripe-js/reference under section Elements options, I can pass my existing CSS classes but my code below didn't work.
const customStripeClasses = {
base: 'app-form-default input',
};
class MyPaymentForm extends Component {
render() {
return(
<div>
<CardElement classes={customStripeClasses} />
</div>
);
}
}
Basically, I'm trying to get Stripe Elements form components to use the CSS classes we created for regular HTML elements e.g. input, textarea, etc.
Any idea how I can get this to work?
As far as I can see from the docs you need to use react-stripe-elements to use stripe with react. And CardElement has no prop classes. You can pass css classes to it with className:
import React from 'react';
import {CardElement} from 'react-stripe-elements';
class CardSection extends React.Component {
render() {
return (
<div>
<CardElement className="app-form-default input" />
</div>
);
}
};

Angular form validation and bootstrap styles

I'm quite new with Angular and i'm trying to create a registration form using Angular and Bootstrap 4.
The result i'd like is to use the styles of Bootstrap with the validation of Angular.
More precisely, when validating the form, Angular applies styles (ng-valid, ng-invalid, etc.) in two different places: the input element and the form element.
Two questions:
1) As Bootstrap uses 'has-danger' and 'has-success' instead of 'ng-[in]valid', is it possible to configure angular to use these styles instead of the default one. Currently, i'm considering extending bootstrap by adding the angular styles (with #extend has-danger/success)
2) Angular applies the style to the input and form elements whereas bootstrap expects it on the form-group element. Is it possible to have angular put the style there instead of the input element (or both?)
I'm using reactive forms and i'd like to avoid things like (not tested):
<form>
<div class="form-group" [class.has-error]="!fg.get('username').valid" [class.has-success]="fg.get('username').valid">
<label>Username</label>
<input formControlName="username" type="text"/>
</div>
</form>
Is there a simple way (not too verbose) of achieving this?
If you're using SASS you can do the following with out needing to rewrite all the css.
.ng-touched.ng-invalid {
#extend .is-invalid;
}
Note: you'll need to be importing bootstrap as part of your SASS build instead of reference it directly.
If you're not using SASS it's pretty to install see here
Angular CLI SASS options
Another option is this directive:
import {Directive, HostBinding, Self} from '#angular/core';
import {NgControl} from '#angular/forms';
#Directive({
selector: '[formControlName],[ngModel],[formControl]',
})
export class BootstrapValidationCssDirective {
constructor(#Self() private cd: NgControl) {}
#HostBinding('class.is-invalid')
get isInvalid(): boolean {
const control = this.cd.control;
return control ? control.invalid && control.touched : false;
}
}
It simply adds the is-invalid class to each field, if the field is touched or invalid. It basically behaves the same as Oliver's SASS-solution, but get's along without SASS and might also have a smaller compiled output.
The best idea that came to me while looking at the angular docs is to use a directive.
My implementation works only with Reactive forms and if the element you want to apply the style contains the form control (which, if you use bootstrap is the case). Should be extended for compatibility with select and textarea.
import { Directive, ElementRef, Input, OnInit } from '#angular/core';
import { FormControl, FormGroup } from '#angular/forms'
#Directive({ selector: '[formValidationStyle]' })
export class FormValidationStyleDirective implements OnInit {
#Input('formValidationStyle') private formGroup: FormGroup;
private component: FormControl;
static VALID_STYLE: string = 'has-success';
static INVALID_STYLE: string = 'has-danger';
constructor(private el: ElementRef) { }
ngOnInit(): void {
let componentName: string;
let inputElement = this.el.nativeElement.querySelector('input');
if (inputElement) {
componentName = inputElement.getAttribute('formControlName');
}
if (!componentName) {
console.error('FormValidationStyleDirective: Unable to get the control name. Is the formControlName attribute set correctly?')
return;
}
let control = this.formGroup.get(componentName)
if (!(control instanceof FormControl)) {
console.error(`FormValidationStyleDirective: Unable to get the FormControl from the form and the control name: ${componentName}.`)
return;
}
this.component = control as FormControl;
this.component.statusChanges.subscribe((status) => {
this.onStatusChange(status);
});
this.onStatusChange(this.component.status);
}
onStatusChange(status: string): void {
let cl = this.el.nativeElement.classList;
if (status == 'VALID') {
cl.add(FormValidationStyleDirective.VALID_STYLE)
cl.remove(FormValidationStyleDirective.INVALID_STYLE)
} else if (status == 'INVALID') {
cl.add(FormValidationStyleDirective.INVALID_STYLE)
cl.remove(FormValidationStyleDirective.VALID_STYLE)
}
}
}
Example:
The component:
#Component({
selector: 'security-register',
templateUrl: './register.component.html'
})
export class RegisterComponent {
registerForm: FormGroup;
constructor(private http: Http, private fb: FormBuilder) {
this.registerForm = this.fb.group({
username: ['', Validators.required]
});
}
}
And its template:
<form [formGroup]="registerForm" novalidate>
<div class="form-group" [formValidationStyle]="registerForm">
<label class="form-control-label" for="dbz-register-username">Login</label>
<input formControlName="username" type="text" class="form-control" id="dbz-register-username" required>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Register</button>
</div>
</form>

Resources