I have a body of clarity forms that have been prepared for an Angular application and I'm trying to use them in React. However even getting the simplest form to work is beyond me right now, there's inadequate examples and documentation and I'm not a frontend developer. Based on the almost zero examples I can find I'm guessing very few people are using Clarity Forms in React.
Here's an example form with multiple attempts to get the CdsInput field to do something. Oddly I got onClick to work but I can't type in the field on the form when it displays.
render() {
return (
<main cds-layout="p:lg vertical gap:lg" cds-text="body">
<h1 cds-text="heading">Clarity in React</h1>
{this.state.show ? (
<CdsAlertGroup status="warning">
<CdsAlert onCloseChange={() => this.setState({ show: false })} closable>Hello World</CdsAlert>
</CdsAlertGroup>
) : (
''
)}
<CdsButton status="success" onClick={() => this.setState({ show: true })}>
Show Alert
</CdsButton>
<CdsInput type="text" id="formFields_5" placeholder="Email" defaultValue="DEFAULT TEXT!" onClick={() => this.setState({ show: false })} >
Text inside tags
</CdsInput>
</main>
);
}
So clicking on the field influences the alert so onClick works, but I can't type in the box and it's empty.
I've consulted the example React app on the Clarity Design System website, but it only shows some components and icons, it gives no example of input/select/interactive controls except buttons.
I am aware that React doesn't support WebComponents and so Clarity Forms isn't a natural fit, but when I import #cds/react am I compensating for this deficiency or do I also have to put a ref on the CdsInput ... I did try that but got too many errors about types and other things:
inputRef: React.RefObject<typeof CdsInput>;
constructor(props: any) {
super(props);
this.state = {
show: false,
};
this.inputRef = React.createRef<typeof CdsInput>();
}
componentDidMount() {
this.inputRef.current.nativeElement.then(element => {
element.focus();
});
}
render() {
return (
... <CdsInput ref={this.inputRef} >HEY THERE</CdsInput> ...
Does anyone know of a simple but functional example of a Clarity Form working in React using #cds/react that I could refer to?
Related
I would like to realize a textfield and a dropdown. When users select an option in the dropdown, the selection will be written to the textfield. And users can write whatever they want in the textfield; the dropdown list is supposed to give users some possible examples/ideas.
It's more or less like a combobox, but I find combobox is always one line (please correct me if I'm wrong). I would expect the textarea to be big and have several lines.
I have written the following code, one thing I would like to improve is that, after selecting an option, I would like the dropdown button to always show Examples of sentences rather than the selected option.
Does anyone know how to achieve this?
I'm open to other third-party components that could realize similar logics.
StackBlitz: https://stackblitz.com/edit/react-ts-yrhmfn?file=App.tsx,index.tsx
import {
FluentProvider,
webLightTheme,
} from '#fluentui/react-components';
import {
Dropdown,
Option
} from '#fluentui/react-components/unstable';
import { TextField } from '#fluentui/react';
import * as React from 'react';
export default class Grouped extends React.Component<{}, { value: any }> {
constructor(props) {
super(props);
this.state = { value: '' };
}
land = ['A long sentence', 'Another long sentence', 'Another another long sentence'];
render() {
return (
<div>
<FluentProvider
className="fluent-provider"
style={{ display: 'flex' }}
theme={webLightTheme}
>
<Dropdown
placeholder="Examples of sentences"
onOptionSelect={(e, data) => {
if (data.optionText !== undefined)
this.setState({ value: data.optionText });
}}
>
{this.land.map((option) => (
<Option key={option}>{option}</Option>
))}
</Dropdown>
</FluentProvider>
<br/>
<TextField
label="Write a sentence:"
value={this.state.value}
multiline
rows={3}
autoAdjustHeight
resizable={false}
/>
</div>
);
}
}
Well, I can solve this but it's a bit of a hack :) My professional suggestion is to consider a different third party library. I looked at the FluentUI and there doesn't seem to be a way to control the currently selected value.
If there were, you could simply set the currently selected value to undefined. Barring that, here's some code that achieve what you're asking for:
{this.state.visible && (
<Dropdown
placeholder="Select an animal"
onOptionSelect={(e, data) => {
if (data.optionText !== undefined) {
this.setState({ value: data.optionText, visible: false });
setTimeout(() => {
this.setState({ value: data.optionText, visible: true });
}, 0);
}
}}
>
{this.land.map((option) => (
<Option key={option}>{option}</Option>
))}
</Dropdown>
)}
What this code does is essentially "unload" the dropdown after a selection is made and then reload it one tick later, which resets its internal state. It's definitely a "hacky" solution, but it gets the job done.
The dropdown uses slots, so actually it's really easy to achieve. You can simply overwrite the props of the underlying button to display always the same text:
<Dropdown
button={{children: "Placeholder"}}
>
<Option>A</Option>
<Option>B</Option>
<Option>C</Option>
<Option>D</Option>
</Dropdown>
I'm trying to use Carbon Design System for a project, and I need some help with the UI Shell.
The transition of the right sidebar is not working properly.
Here is the working example, see how smooth it opens and closes (see live example):
Here is the example with issues. There's no transition (see live example):
I think it's related to how High Order Components work. Here's my theory:
HeaderPanel is being rendered inside the HeaderContainer, which is a High Order Component.
When the state variable switchCollapsed changes, the HeaderContainer is rendered entirely again.
So this would explain why there's no transition.
I'm new to React, and this theory is based on my React knowledge until now. Please correct me if I'm wrong
Here's a piece of the code of the second example (simplified for the brevity of this post). See the entire code here
class App extends React.Component {
constructor(props) {
super(props);
this.toggleSwitch = this.toggleSwitch.bind(this);
this.state = { switchCollapsed: true };
}
toggleSwitch() {
this.setState(state => ({
switchCollapsed: !state.switchCollapsed
}));
}
render() {
return (
<div className="container">
<HeaderContainer
render={({ isSideNavExpanded, onClickSideNavExpand }) => (
<>
<Header aria-label="IBM Platform Name">
<HeaderMenuButton
onClick={onClickSideNavExpand}
isActive={isSideNavExpanded}
/>
<HeaderGlobalBar>
<HeaderGlobalAction onClick={this.toggleSwitch}>
<UserAvatar20 />
</HeaderGlobalAction>
</HeaderGlobalBar>
<HeaderPanel
aria-label="Header Panel"
expanded={!this.state.switchCollapsed}
/>
<SideNav
aria-label="Side navigation"
expanded={isSideNavExpanded}
>
<SideNavItems>
</SideNavItems>
</SideNav>
</Header>
<StoryContent />
</>
)}
/>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Moreover, if I change the property on React Dev Tools, the transition work!
I am working with react and using Ant Design v4.1.0.
I have a form and on submit (onFinish), I send the id to reducer to get all the values of the fields. I am doing so because of my requirement (I've to select the id on the form itself and get all data many times also open same form from many place with specific id). There might be better ways to achieve my requirement but for now I'm doing so.
I am getting the desired data - props (I verified) but I'm not able to update fields with new props.
I have set
class CustomForm extends React.Component {
formRef = React.createRef();
constructor()
render(){
return(
<Form
ref={this.formRef}
onFinish={this.onFinish}
name="customForm"
initialValues=
{{
//(trying) email: this.props.customerData.map((d) => d.email)
}}
>
<Form.Item label="Email" name="email">
<Input />
</Form.Item>
</Form>
)}
}
I read ant design document and it is mentioned initialvalues does not work on state change and we should use setFieldsValue.
When trying I added "formRef" for class based form as per their example but not able to use setFieldValue.
I tried with
componentDidUpdate(){
alert(JSON.stringify(this.props.customerData.map((d) => d.email)));
this.formRef.current.setFieldsValue({
mobileNumber: this.props.customerData
.map((d) => d.mobile_number),
email: this.props.customerData.map((d) => d.email),
});
}
and getting error Cannot read property 'setFieldsValue' of null
How can I set values, actually use setFieldValues?
And why this.formRef is null?
So on onFinish i set loading = true and my return was
(this.state.loading ? <Spin /> : <Form />)
The reason i was getting this.formRef = null.
Now solved the issue.
Thanks
This code works fine if the user selects something from each dropdown menu, but if they forget to make a selection, it will just use the value selected from the previous dropdown menu. Also if they don't make any selection at all and submit, it will obviously submit the default value stored in the state which is "0".
Anyone happen to have a workaround for this? Thanks.
export class Content extends Component {
constructor(props){
super(props)
this.state = {
selectedOption: 0
}
}
handleOptionChange = e => {
this.setState({
selectedOption: e.target.value
})
}
handleSubmit = e => {
e.preventDefault()
}
render() {
let snowboardItems = this.props.snowboards.map((board,index) => {
return <div><form onSubmit={this.handleSubmit}>
<li key={index} className="list_item">
<div className="content_div1">
<h3>{board.name}</h3>
<h3>$ {board.price}</h3>
<h4>{board.terrain}</h4>
<h4>Shape: {board.shape}</h4>
<p>Board Length:</p>
<select value={this.state.selectedOption} onChange={this.handleOptionChange}>
{board.length.map((item, index) =>
<option value={item} key={index}>{item}</option>
)}
</select> cm
</div>
<div className="content_div2">
<button className="content_button" type="submit" onClick={() => this.props.addToCart({board}, this.state.selectedOption)}>Add to Cart</button>
<img className="image" src={board.imageurl} />
</div>
</li>
</form>
</div>
})
This is really a case where you should separate this into two components: one to render the list of items (you could do this in the parent passing the props too), and another to render the item and possibly handle its state.
If for some reason you can't though, you'll probably want to separate each board option into its own property on state. Here's an example where state is updated dynamically:
https://codesandbox.io/embed/snowboards-pl9r5
You should always code defensively, so in the example there's a "short circuit" check to make sure that a length was selected before adding it to the cart. Also the select field is marked as required so that you can use HTML5 as another fallback validator.
You can check it by trying to add an item without a length and also selecting different options and adding them to the cart (logging them in the console).
On another note: I changed it to more specific keys because mapping multiple lists and using the index as a key will result in duplicate keys. Keys are how react knows which item is which, and you don't want to confuse react!
P.S. Way to bum me out giving a snowboard example in the summer! lol Happy hackin'
Dear genius StackOverflowians,
I am trying to write an app where users can configure questions and answers, along with defining help text for each question. I'm writing this in typescript React - which is handy when you want to define types of answers for questions.
I want to have a button next to the question that shows/hides a styled document. The button looks and works great, but the document that is hidden/shown doesn't get the generated style class that ought to be associated with it.
Here is the functional component to display the help document:
let HelpTextBody = function(props: { helpDocument: DocumentationStore }) {
return (
<div>
{props.helpDocument.toReallySimple().map(tok => {
return React.createElement(tok.tag, null, tok.content);
})}
</div>
);
};
tok comes from a custom class DocumentationStore that is pretty much a wrapper around markdown-it, a handy js library for working with md files, which I would like my users to write their helptext in (and store it that way).
So I do this (in a different module for DocumentationStore class):
toReallySimple(): MdJson[] {
let bigParsed = this.md_.parse(this.Text, null).filter(
t => return t.type == "inline" || t.type.indexOf("open") > 0
});
Later on, I style HelpTextBody with:
const StyledHelpDocument = styled(HelpTextBody)`
background-color: lightslategray;
`;
Keeping it simple now so I can just see if it's working...
I then include it in a component with the button that I export:
class HelpText extends React.Component<helpProps, helpState> {
constructor(props: helpProps) {
super(props);
this.state = {
hidden: true
};
}
swapHidden() {
this.setState({
hidden: !this.state.hidden
});
}
render() {
if (this.state.hidden) {
return (
<span>
<StyledButton
itemScope={this.state.hidden}
onClick={() => this.swapHidden()}
>
Need Help?
</StyledButton>
</span>
);
} else {
return (
<span>
<StyledButton onClick={() => this.swapHidden()}>
Hide Help
</StyledButton>
<StyledHelpDocument helpDocument={this.props.helpDocument} />
</span>
);
}
}
So I webpack it all and get stuff into the browser, and what I get back is this style tag (after clicking the button), which looks right:
<style data-styled-components="">
/* sc-component-id: sc-bdVaJa */
.sc-bdVaJa {} .gscXTZ{background:red;color:white;font-size:1em;margin:1em;padding:0.25em 1em;border:2px solid red;border-radius:3px;}.iwtdKP{background:white;color:red;font-size:1em;margin:1em;padding:0.25em 1em;border:2px solid red;border-radius:3px;}
/* sc-component-id: sc-bwzfXH */
.sc-bwzfXH {} .hAvMqj{background-color:lightslategray;}</style>
But my html for the document is missing the reference to the class (.hAvMqj I guess?)
<span>
<button class="sc-bdVaJa iwtdKP">Hide Help</button>
<div><p>Here the text is grey</p></div>
<!-- ^This^ is the StyledHelpDocument... no class!-->
</span>
So where am I going wrong? I don't understand why it generates the style, and the component's HTML renders... but the class isn't applied to the component! What do you think?
Your styled-components class isn't being applied because you're styling a custom component, but you haven't included className as a prop. Add className as an optional prop in the component you're styling, and also be sure to apply className somewhere in the render method for that component. For your case, it should be added like so:
let HelpTextBody = function(props: { helpDocument: DocumentationStore, className: string }) {
return (
<div className={props.className}>
{props.helpDocument.toReallySimple().map(tok => {
return React.createElement(tok.tag, null, tok.content);
})}
</div>
);
};