I searched through storybook's documentation for react and I can't seem to find how to make the object control for my argument appear collapsed by default instead of having to collapse it manually.
this is what I did
data: {
control: { type: 'object' },
table: { defaultValue: { summary: 'Object' } },
collapsed: true, // I want to find out if there is something like this
},
and this is what I was expecting
The option to configure this does not exist, unfortunately. Inspired by this comment regarding having the RAW-view open by default, I made a somewhat hacky solution, query all the spans at the top level for collapsing their content and trigger a click using JavaScript.
In the file manager.js add the following to make this work:
const observer = new MutationObserver(() => {
// Query the spans for collapsing objects.
const objectCollapseSpans = [...document.querySelectorAll('.rejt-tree > .rejt-object-node > span')];
// Query the spans for collapsing array of objects.
const arrayCollapseSpans = [...document.querySelectorAll('.rejt-tree > .rejt-array-node > span')];
const collapseSpans = [...arrayCollapseSpans, ...objectCollapseSpans];
for (const span of collapseSpans) {
if (span.className !== 'closed') {
span.click();
}
span.className = 'closed'
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
})
Related
#storybook/addon-controls is fun, however I cannot find a way to disable control generation for a given arg. Lets say I have a component prop that is an event handler and I obviously do not want it to have a control. So I want it to appear in the list of props with the name, type and description, but no control. How do I do that?
this was recently added: https://github.com/storybookjs/storybook/pull/11388
Essentially you should be able to use control.disable within argTypes for a given arg.
Suppose you have a story with foo and bar properties (auto-generated or otherwise) and you want to hide the foo row completely and disable controls for the bar row on a specific story:
MyStory.argTypes = {
foo: { table: { disable: true } },
bar: { control: { disable: true } },
};
Here's the entry in the docs.
Cheers
About a year ago include and exclude of args was added (link to the PR).
In the documentation it is referred to as "Filtering Controls".
You can choose which arguments to include and/or exclude by string, array or regular expression.
Usage example (from the docs):
const Template = (args) => ({
//👇 Your template goes here
});
ArrayInclude = Template.bind({})
ArrayInclude.parameters = { controls: { include: ['foo', 'bar'] } };
RegexInclude = Template.bind({})
RegexInclude.parameters = { controls: { include: /^hello*/ } };
ArrayExclude = Template.bind({})
ArrayExclude.parameters = { controls: { exclude: ['foo', 'bar'] } };
RegexExclude = Template.bind({})
RegexExclude.parameters = { controls: { exclude: /^hello*/ } };
I have a React address form which is config driven, and each element could either be a text <input> or a <select> dropdown. When trying to fill in the form using the code below, the text inputs are populated successfully, but the select element can't be found. If I remove the select elements from the loop and select them individually afterwards, it works fine. The MOCKS.deliveryAddress values are just strings.
const addressFields = {
addressLine2: Selector('[data-testid="input-addressLine2"]'),
addressLine1: Selector('[data-testid="input-addressLine1"]'),
addressLine3: Selector('[data-testid="input-addressLine3"]'),
addressLine4: Selector('[data-testid="input-addressLine4"]'),
postalCode: Selector('[data-testid="input-postalCode"]'),
};
const fieldConfig = {
addressLine1: 'text',
addressLine2: 'text',
addressLine3: 'text',
addressLine4: 'select',
postalCode: 'text',
};
const enterAddress = async () => {
await Promise.all(
Object.keys(addressFields).map(async (field) => {
if (fieldConfig[field] === 'text') {
if (MOCKS.deliveryAddress[field]) {
await t.typeText(
addressFields[field],
MOCKS.deliveryAddress[field],
{
replace: true,
},
);
}
} else {
await t.click(addressFields[field]);
await t.click(
addressFields[field]
.find('option')
.withText(MOCKS.deliveryAddress[field]),
);
}
}),
);
};
}
I get the error 1) The element that matches the specified selector is not visible.
Am I doing something wrong here in how I handle the selector inside a map?
Thanks in advance!
According to the TestCafe documentation, the element is considered as 'visible' if it does not have display: none or visibility: hidden CSS properties and has non-zero width and height. Using the browser development tool to investigate the properties of elements used in tests.
Turns out I was doing it wrong! I should have been chaining the click events for opening the dropdown and selecting an option, rather than awaiting the select click and then awaiting the option click. E.g.
await t
.click(addressFields[field])
.click(
addressFields[field]
.find('option')
.withText(MOCKS.deliveryAddress.addressLine4),
);
I am using Fluent UI DetailsList. My table looks like below:
I need filters below every column (text or drop-down) as shown below:
Please let me know if this is possible? Or maybe a way to display custom header (using html) ?
This actually turned out to be easier than I thought it'd be...
If you're ok with clicking the column header to reveal the choices (vs having the dropdown directly under the title) then this can be achieved using the ContextualMenu component in conjunction with DetailsList. I got it working by tweaking from the variable row height example in the official docs: https://developer.microsoft.com/en-us/fluentui#/controls/web/detailslist/variablerowheights.
Add a ContextualMenu underneath your DetailsList:
<DetailsList
items={items}
columns={columns}
/>
{this.state.contextualMenuProps && <ContextualMenu {...this.state.contextualMenuProps} />}
Inside your column definition, set the hasDropdown action so the user gets a UI indicator that they can/should click the header, and call a contextMenu method (note I'm using onColumnContextMenu as well as onColumnClick so it doesn't matter if they left or right click the header:
{
key: 'dept',
name: 'Department',
fieldName: 'dept',
minWidth: 125,
maxWidth: 200,
onColumnContextMenu: (column, ev) => {
this.onColumnContextMenu(column, ev);
},
onColumnClick: (ev, column) => {
this.onColumnContextMenu(column, ev);
},
columnActionsMode: ColumnActionsMode.hasDropdown,
}
When the onColumnContextMenu method gets invoked, we need to build the context menu properties that will get consumed by the ContextualMenu component. Note the dismissal method as well, which clears out the state so the menu is hidden.
private onContextualMenuDismissed = (): void => {
this.setState({
contextualMenuProps: undefined,
});
}
private onColumnContextMenu = (column: IColumn, ev: React.MouseEvent<HTMLElement>): void => {
if (column.columnActionsMode !== ColumnActionsMode.disabled) {
this.setState({
contextualMenuProps: this.getContextualMenuProps(ev, column),
});
}
};
Finally, inside of getContextualMenuProps you need to determine what the options should be for the user to click. In this example, I'm simply giving sort options (you'll need to add an onClick handler to actually do something when the user clicks the item), but I'll use the column to determine what those items should actually be and paint the filters into the items collection so the user can select one to filter.
private getContextualMenuProps = (ev: React.MouseEvent<HTMLElement>, column: IColumn): IContextualMenuProps => {
const items: IContextualMenuItem[] = [
{
key: 'aToZ',
name: 'A to Z',
iconProps: { iconName: 'SortUp' },
canCheck: true,
checked: column.isSorted && !column.isSortedDescending,
},
{
key: 'zToA',
name: 'Z to A',
iconProps: { iconName: 'SortDown' },
canCheck: true,
checked: column.isSorted && column.isSortedDescending,
}
];
return {
items: items,
target: ev.currentTarget as HTMLElement,
directionalHint: DirectionalHint.bottomLeftEdge,
gapSpace: 10,
isBeakVisible: true,
onDismiss: this.onContextualMenuDismissed,
}
}
Note the target on the ContextualMenuProps object, which is what tells the ContextualMenu where to lock itself onto (in this case, the column header that you clicked to instantiate the menu.
Detail list filter for each column without context menu -
https://codesandbox.io/s/rajesh-patil74-jzuiy?file=/src/DetailsList.CustomColumns.Example.tsx
For instance - Providing filter in text field associated with each column will apply filter on color column.
I have a custom tooltip in react-chartjs-2;
I found a solution of making custom tooltip, but my tooltip is always visible, in that solution tooltip hides when tooltip.opacity is 0, but in my case tooltip opacity is always 1, can smbd help me pls?
tooltips: {
enabled: false,
mode: 'x',
intersect: false,
custom: (tooltipModel) => {
if (tooltipModel.opacity === 0) {
// never called because opacity is always 1
this.hide();
return;
}
// const position = this.chartRef.current.chartInstance.canvas.getBoundingClientRect();
// set position of tooltip
// const left = position.left + tooltipModel.caretX;
// const top = position.top + tooltipModel.caretY;
// set values for display of data in the tooltip
const date = tooltipModel.dataPoints[0].xLabel;
const value = tooltipModel.dataPoints[0].yLabel;
// this.setPositionAndData(top, left, date, value);
},
Just to clarify for any other person who needs help on this.
When you create your handle for a custom toolbar, you need to pay attention to not overwrite the this(scope) object. Try with arrow function and remove the bind, the fn will get automatically the new scope and the opacity will be update when you move out from a chart bar/line etc.
The same issue will happen with the legend if you try to overwrite the onClick function using inline arrow function or functions. Some examples bellow.
_tooltip = (tooltipModel) => {
...
}
_legendOnClick = (ev) => {
ev.preventDefault()
}
render() {
const defaultOpt = {
legend: {
onClick: this._legendOnClick
},
tooltips: {
enabled: false,
custom: this._tooltip,
mode: 'index'
}
}
}
If you want to improve perfomance, you should remove the defaultOpt from the render method.
That's
Instead of this:
intersect: false,
custom: (tooltipModel) => {
if (tooltipModel.opacity === 0) {
use this workaround:
intersect: false,
custom: function(tooltipModel){
let hit=this._active[0].inRange(this._eventPosition.x, this._eventPosition.y);
if (tooltipModel.opacity === 0 || !hit) {
make sure not to use arrow function to keep 'this'.
In my case the root of the problem was that I defined the 'options' object in the render function of my component along with the 'custom' tooltip handler and called a setState from the inside of it - which caused an other render call immediately. This broke down the tooltip handling of chart.js. Moving the handler outside of the render function solved it without needing the above workaround.
I trying Select item in dx-tree-view, my treeview config:
$scope.treeViewOptions = {
bindingOptions: {
dataSource: 'localArray',
searchValue: "searchValue",
},
keyExpr: 'id',
displayExpr: 'caption',
parentIdExpr: 'parentId',
dataStructure: 'plain',
selectedExpr: 'isSelected',
onItemClick: function (e) {...
I added selectExpr:'isSelected' option, and trying select my item use it:
$scope.localArray[0].isSelected = true;
$scope.localArray = $scope.localArray;
but it don't works, may be somebody have ideas how i can do it ?
Thanks for Your answers!
In DevExtreme v.15.2 tree view selection works only with the showCheckBoxesMode: 'normal' option.
$scope.treeViewOptions = {
// tree view config...
showCheckBoxesMode: 'normal'
};
The sample is here.
But, if you want to apply a custom style to the item with the isSelected field, you can do it manually. Just use the onItemRendered event and check if item is selected:
onItemRendered: function(args){
if(args.itemData.isSelected) {
args.itemElement.css("color", "green");
}
}
Sample.