Svelte - `&:nth-child()` doesn't work for elements which created by {#each} - css-selectors

<script lang="ts">
let buttons: Array<{ buttonName: string; className: string; id: number }>;
buttons = [
{ buttonName: 'NEW GAME', className: 'home-start', id: 1 },
{ buttonName: 'SETTINGS', className: 'home-setup', id: 2 },
{ buttonName: 'HOW TO PLAY', className: 'home-help', id: 3 },
];
</script>
<style land="sass">
.buttons
:nth-child(n+2)
background-color: red
</style>
<template>
<div class="buttons">
{#each buttons as button (button.id)}
<Button
className="{button.className} button"
on:click={()=>{console.log(button.className)}}>
{button.buttonName}
</Button>
{/each}
</div>
</template>
The nth-child() selector doesn't work, but it works on those elements which were hard coded in.
How can I solve this?
This is my first question here, and my english isn't good enough though, but I still hope it makes sense. Thanks for your help!

The element you render in the #each is not part of this component, so the styles will be discarded. This is because svelte has no way to know to which element to apply this style. For all it's worth your Button component looks like this
<div></div>
<button></button>
You can get around this by adding :global to your selector:
.buttons > :global(:nth-child(n+2) {
background-color: red
}
(This uses regular css, but you should be able to translate it to sass)
Docs about :global

Related

TinyMCE React add custom component to toolbar

The bounty expires in 6 days. Answers to this question are eligible for a +500 reputation bounty.
badcoder wants to draw more attention to this question:
Need more attention to this question. The one response that has been provided to this question does not correctly answer it unfortunately
When creating a TinyMCE editor in React, it is possible to add a custom button to the toolbar using the following code:
<Editor
...
init={{
...
setup: (editor) => {
editor.ui.registry.addButton('test' {
text: 'Test',
onAction: () => console.log('Test')
});
}
}}
/>
Besides addButton, there are other options such as addIcon, addMenuItem, and addSidebar. However, I can't figure out how to include my own custom component.
Say I wanted to add a very simple div/component
<div>
<ul>
<li>Test 1</li>
<li>Test 2</li>
</ul>
</div>
or
<TestComponent />
to the end of the toolbar, how would I do this?
Any ideas?
You need to add the key test to the toolbar property in your init object
<Editor
init={{
toolbar: "test",
setup: (editor) => {
editor.ui.registry.addButton('test' {
text: 'Test',
onAction: () => console.log('Test')
});
}
}}
/>

React Fluent UI dropdown disabled tooltip on hover

I have a requirement to add tooltip on hover to disabled options in a dropdown in React fluent UI.
I am able to add tooltip to singular component using https://www.npmjs.com/package/#fluentui/react-tooltip
<Tooltipcontent="Example tooltip">
<Button/>
</Tooltip>
but how to add similar behaviour to dropdown options and only for disabled options
like: "Disabled cause of non avilability"
sample dropdown fluent ui code
const options: IDropdownOption[] = [
{ key: 'fruitsHeader', text: 'Fruits', itemType: DropdownMenuItemType.Header },
{ key: 'apple', text: 'Apple' },
{ key: 'banana', text: 'Banana' },
{ key: 'orange', text: 'Orange', disabled: true },
];
export const DropdownBasicExample: React.FunctionComponent = () => {
return (
<Stack tokens={stackTokens}>
<Dropdown
placeholder="Select an option"
label="Basic uncontrolled example"
options={options}
styles={dropdownStyles}
/>
</Stack>
);
};
Thanks
Fluent UI renders every disabled option as a button element with the disabled attribute, which makes it non-interactive by default.
Here's a method to solve this that I believe is also fairly accessible:
First, define your array of IDropdownOption items so that they conditionally set the disabled and title properties:
const options: IDropdownOption[] = [
{ key: 'apple', text: 'Apple' },
{ key: 'orange',
text: 'Orange',
disabled: isOrangeDisabled,
title: isOrangeDisabled ? "This is a disabled tooltip" : ""
},
];
You're also going to need to define a custom rendering function for the items in order to apply a nice tooltip:
<Dropdown onRenderOption={onRenderOption} />
and then define a function like this in your component:
const onRenderOption = (option: IDropdownOption): JSX.Element => {
return (
<>
{option?.disabled && (
<div className="interactive">
<TooltipHost content={option.title}>
<span>{option.text}</span>
</TooltipHost>
</div>
)}
{!option?.disabled && (
<span>{option.text}</span>
)}
</>
);
};
Finally, that interactive CSS class needs to be defined in your CSS file. This will override the browser's default behaviour of making disabled elements non-interactive:
.interactive {
pointer-events: auto;
}
Some things to note:
The reason the title is set to an empty string when the option is not disabled is so that it doesn't have a string value when the interactive item is rendered. Without this, the browser will render the tooltip when you hover on a selectable item, which looks ugly.
Using the title attribute should make the component pretty usable for screen readers and other assistive technology (though I am far from an expert)
The template only renders the TooltipHost and interactive class when the object is disabled, so that the tooltip and that behaviour only kick in when the option is disabled. Because the underlying option is still disabled, you still won't be able to select it.

How to apply styles to TabPane in new Antd Tabs component

This is my old implementation of the Tabs component in Ant Design.
const tabList = [
{
key: "tab1",
label: "Tab1",
children: <Tab1 />,
},
{
key: "tab2",
label: "Tab2",
children: <Tab2 />,
},
];
<Tabs onChange={onTabChange} activeKey={selectedTab}>
{tabList.map((tab) => {
const { key, label, children } = tab;
return (
<Tabs.TabPane
key={key}
tab={label}
style={{ margin: "1.5rem auto 1.5rem" }}
>
{children}
</Tabs.TabPane>
);
})}
</Tabs>;
In the new version ( > 4.23.0 ) the boilerplate got reduced.
I can simply pass my tabList to my Tabs as a prop items.
The new code looks something like this.
<Tabs items={tabList} />
But I had an issue with styling.
I am adding top and bottom margins to all of my TabPane components.
To get that margin in the new implementation. I had to do something like this.
{
key: "tab1",
label: "Tab1",
children: <Tab1 style={{margin: "1.5rem 0 1.5rem"}} />,
},
Here I am facing two issues.
I need to add this for all my tabs in the tabList
I need to have a div in every component spreading the props that are passed above.
function Tab1(props) {
return <div {...props}>JSX for original Tab1</div>;
}
Is there a better way to do this?
Higher order component can solve this issue
Use a higher Order component like <TabPaneWrapper> or <TabChildrenWrapper>. This component does nothing but to wrap your children (<TabPane>) with a div and give the styles you require.
Component:
export function TabPaneWrapper({
children,
...props
}){
return (
<div style={{ margin: "1.5rem auto 1.5rem" }} {...props}>
{children}
</div>
);
}
Usage:
const tabList = [
{
key: "tab1",
label: "Tab1",
children: <TabPaneWrapper> <Tab1 /> </TabPaneWrapper>,
},
{
key: "tab2",
label: "Tab2",
children: <TabPaneWrapper> <Tab2 /> </TabPaneWrapper>,
},
];
If you have more tabs or use this tabs component in multiple places. You will find TabPaneWrapper to be repetitive. In such case,
You can create a custom Tabs component like <CustomTabs/> which takes the tabList mentioned in the question.
Instead of wrapping every tab in the tabList with <TabPaneWrapper/>. You can loop this list inside the <CustomTabs/> component to generate the tabList mentioned above and then pass it to the Ant Desing <Tabs/> component.

Ability to add div element next to chart using plotly.js

I am trying to add an external div element(Summary Panel) on the right side of the bar chart I have implemented using react-plotly.js.
The div element would pop-up next to the chart when onClick event is fired on the chart. The panel would display the information related to the bar that was clicked. The data object based on which the bar chart is created is:
const barData = [
{ endTime: '', startTime: '', duration: 6, initiatorUsername: 'abc', title: 'abc1', aTitle: 'Manager', outcome: 'Success' },
{ endTime: '1521203405', startTime: '1520389805', duration: 7, initiatorUsername: 'defs', title: 'Senior Analyst', aTitle: 'Manager', outcome: 'Failure' }
];
I haven't seen any such example or any documentation related to add external div element to the chart. Is it possible to link chart to the external div element ?
I did attempt to implement it by doing the following:
<Plot
data={this.prepData(timelineData)}
onClick={(data) => {
this.renderCustomPanel(data);
}
onHover={(hover) => this.getHoverInfo(hover)}
type={'bar'}
layout={layout}
style={{ width: '95%' }}
/>
renderCustomPanel(e) {
const panelInfo = timelineData.map(i => `<span className="panel-info">
<span className="tooltip-value" style='font-size:15px;display:block'>${i.duration} days <br> Start time: ${moment.unix(i.startTime).format('MMM-DD-YYYY h:mm:ss')} <br> End time:${moment.unix(i.endTime).format('MMM-DD-YYYY h:mm:ss')}</span></span>`);
return panelInfo;
}
The onClick function does call the function but doesn't display the div element. I did try applying css styles to the element but nothing works. Firstly, how do I make a panel display onClick?
Alternate solution that comes to my mind is to make panel a separate sibling component. In that case, How do I pass the data to it such that in the description section it displays the information related to the bar that was clicked ?
class SummaryPanel extends Component {
constructor(props) {
super(props);
this.state = {
isActive: true
};
}
render() {
return (
<div className='summaryPanel'>
<Card
label='Summary panel'
heading=''
description=''
/>
<button type="button" className="close" data-dismiss="alert" aria-label="Close" onClick={() => this.hideAlert()}><span aria-hidden="true">×</span></button>
</div>
);
}
}

Angular2 animation - unable to animate on ngFor loop on component

I need help please. I have read a lot on animation in angular and have applied it successfully on simple solutions. In my search for over 45 min I am unable to find a question that relates to my situation.
I have a main component called CareerListingComponent. It gets job offers (career) from service. Then it prints box for each job using ngFor loop using another component called CareerBoxComponent.
CareerListingComponent has dropdown using which you can shortlist your selection: -
<select class="form-control" id="idSelDepartment" name="dept"
[ngModel]="searchDept" (ngModelChange)="selectValueChangedDept($event)">
<option value="">Career Area - All</option>
<option *ngFor="let dept of arrDept" value="{{dept}}">{{dept}}</option>
</select>
Everything works fine except animation. If I select something from dropdown, boxes show and hide but boxes change very fast with no effects.
I have used "SearchPipe:searchCountry:searchCity:searchDept" Pipes to filter array of Careers object.
<div class="row">
<div class="container grid jobs">
<app-career-box
*ngFor="let career of careers | SearchPipe:searchCountry:searchCity:searchDept
let index = index;
let isOdd = odd;
let isEven= even;"
[#visibilityChanged]="'in'"
[career]="career"
></app-career-box>
</div>
</div>
As you can see I am using the property [#visibilityChanged]="'in'" to fadeIn and fadeOut but it does not work.
My animation code in the CareerListingComponent is
animations: [
trigger('visibilityChanged', [
state('in' , style({ opacity: 1, transform: 'scale(1.0)' })),
state('out', style({ opacity: 0, transform: 'scale(0.0)' })),
transition('1 => 0', animate('700ms')),
transition('0 => 1', animate('700ms'))
])
]
my guess is that my box component called CareerBoxComponent with selector app-career-box does not notify parent component about its show and hide.
Source code of CareerBoxComponent
#Component({
selector: 'app-career-box',
templateUrl: './career-box.component.html',
styles: []
})
export class CareerBoxComponent implements OnInit {
#Input() career: Career;
constructor() { }
gotoDetailUrl() {
window.location.href = this.career.detailUrl;
console.log('Redirect to '+ this.career.detailUrl);
}
}
I think the reason why animations are not being applied on your app-career-box component is because they are not block elements. I may be wrong but applying display: block; style on the host does the trick.
Here is how I applied the style on CareerBoxComponent:
#Component({
selector: 'app-career-box',
template: `...`
styles: [`
:host {
display: block;
}
`]
})
export class CareerBoxComponent {
}
Plunkr Demo: https://plnkr.co/edit/RYxZoS6thSO7iaU7YEPK?p=preview

Resources