Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Forms] Add <Label> and <FormGroup> examples #2433

Closed
wants to merge 15 commits into from
1 change: 1 addition & 0 deletions packages/core/src/common/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export const HOTKEY_COLUMN = `${HOTKEY}-column`;
export const HOTKEY_DIALOG = `${HOTKEY}-dialog`;

export const LABEL = `${NS}-label`;
export const LABEL_TEXT = `${NS}-label-text`;
export const FORM_GROUP = `${NS}-form-group`;
export const FORM_CONTENT = `${NS}-form-content`;
export const FORM_HELPER_TEXT = `${NS}-form-helper-text`;
Expand Down
14 changes: 7 additions & 7 deletions packages/core/src/components/forms/_form-group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Form groups
Markup:
<div class="#{$ns}-form-group">
<label class="#{$ns}-label" for="example-form-group-input-a">
Label A
<span class="#{$ns}-label-text">Label A</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just use <strong> tags if all you want is bold? it's both semantic and requires no additional styles or classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cause if we change this in the future, we'll also have to change the tag. poor maintanability

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but that tag isn't going anywhere! it's the semantic browser way of saying "make this text stronger," which is exactly what you're trying to do here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please try it. i'm quite confident it'll work beautifully and we won't have to add another -text class for one style rule.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I meant is that I don't like tying a visual to a specific tag. if in the future I want to get rid of bold and do another visual style, I'll have to change the tag because <strong> will no longer make sense.

did it anyway, kind of a bummer tho cause I still need to override the font-weight of the <strong> (default is 700, we want 600)

<span class="#{$ns}-text-muted">(required)</span>
</label>
<div class="#{$ns}-form-content">
Expand All @@ -20,7 +20,7 @@ Markup:
</div>
<div class="#{$ns}-form-group #{$ns}-intent-danger">
<label class="#{$ns}-label" for="example-form-group-input-b">
Label B
<span class="#{$ns}-label-text">Label B</span>
<span class="#{$ns}-text-muted">(required)</span>
</label>
<div class="#{$ns}-form-content">
Expand All @@ -33,7 +33,7 @@ Markup:
</div>
<div class="#{$ns}-form-group">
<label class="#{$ns}-label" for="example-form-group-switch-c">
Label C
<span class="#{$ns}-label-text">Label C</span>
<span class="#{$ns}-text-muted">(required)</span>
</label>
<div class="#{$ns}-form-content">
Expand All @@ -47,7 +47,7 @@ Markup:
</div>
<div class="#{$ns}-form-group #{$ns}-inline">
<label class="#{$ns}-label" for="example-form-group-input-d">
Label D
<span class="#{$ns}-label-text">Label D</span>
<span class="#{$ns}-text-muted">(optional)</span>
</label>
<div class="#{$ns}-form-content">
Expand All @@ -60,7 +60,7 @@ Markup:
</div>
<div class="#{$ns}-form-group #{$ns}-inline #{$ns}-large #{$ns}-disabled">
<label class="#{$ns}-label" for="example-form-group-input-e">
Label E
<span class="#{$ns}-label-text">Label E</span>
<span class="#{$ns}-text-muted">(optional)</span>
</label>
<div class="#{$ns}-form-content">
Expand All @@ -73,7 +73,7 @@ Markup:
</div>
<div class="#{$ns}-form-group #{$ns}-inline">
<label class="#{$ns}-label" for="example-form-group-switch-f">
Label F
<span class="#{$ns}-label-text">Label F</span>
</label>
<div class="#{$ns}-form-content">
<label class="#{$ns}-control #{$ns}-switch">
Expand All @@ -86,7 +86,7 @@ Markup:
</div>
<div class="#{$ns}-form-group #{$ns}-inline #{$ns}-large #{$ns}-disabled">
<label class="#{$ns}-label" for="example-form-group-switch-g">
Label G
<span class="#{$ns}-label-text">Label G</span>
</label>
<div class="#{$ns}-form-content">
<label class="#{$ns}-control #{$ns}-switch #{$ns}-large #{$ns}-disabled">
Expand Down
14 changes: 9 additions & 5 deletions packages/core/src/components/forms/_label.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ Labels

Markup:
<label class="#{$ns}-label {{.modifier}}">
Label A
<span class="#{$ns}-label-text">Label A</span>
<span class="#{$ns}-text-muted">(required)</span>
<input class="#{$ns}-input" style="width: 180px;" type="text" placeholder="Text input" dir="auto" />
</label>
<label class="#{$ns}-label {{.modifier}}">
Label B
<span class="#{$ns}-label-text">Label B</span>
<span class="#{$ns}-text-muted">(optional)</span>
<div class="#{$ns}-input-group">
<span class="#{$ns}-icon #{$ns}-icon-calendar"></span>
Expand All @@ -31,6 +31,10 @@ label.#{$ns}-label {
display: block;
margin: 0 0 ($pt-grid-size * 1.5);

.#{$ns}-label-text {
font-weight: 600;
}

.#{$ns}-input,
.#{$ns}-select,
.#{$ns}-popover-wrapper {
Expand Down Expand Up @@ -75,19 +79,19 @@ label.#{$ns}-label {

Markup:
<label class="#{$ns}-label #{$ns}-disabled">
Label A
<span class="#{$ns}-label-text">Label A</span>
<span class="#{$ns}-text-muted">(optional)</span>
<input disabled class="#{$ns}-input" style="width: 200px;" type="text" placeholder="Text input" dir="auto" />
</label>
<label class="#{$ns}-label #{$ns}-disabled">
Label B
<span class="#{$ns}-label-text">Label B</span>
<div class="#{$ns}-input-group #{$ns}-disabled">
<span class="#{$ns}-icon #{$ns}-icon-calendar"></span>
<input disabled class="#{$ns}-input" style="width: 200px;" type="text" placeholder="Input group" dir="auto" />
</div>
</label>
<label class="#{$ns}-label #{$ns}-disabled">
Label C
<span class="#{$ns}-label-text">Label C</span>
<div class="#{$ns}-select #{$ns}-disabled">
<select disabled>
<option selected>Choose an item...</option>
Expand Down
31 changes: 11 additions & 20 deletions packages/core/src/components/forms/form-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ Form groups support more complex form controls than [simple labels](#core/compon
such as [control groups](#core/components/forms/control-group) or [`NumericInput`](#core/components/forms/numeric-input).
They also support additional helper text to aid with user navigation.

@reactExample FormGroupExample

@## JavaScript API
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're still in the habit of CSS API appearing before JS API so there's no good reason to move only this one.


The `FormGroup` component is available in the __@blueprintjs/core__ package.
Make sure to review the [getting started docs for installation info](#blueprint/getting-started).

This component is a simple wrapper around the CSS API that abstracts away the HTML complexity.

@interface IFormGroupProps

@## CSS API

- Link each label to its respective control element with a `for={#id}` attribute on the `<label>` and
Expand All @@ -17,23 +28,3 @@ Similar to labels, nested controls need to be styled separately.
- Add `.@ns-large` to `.@ns-form-group` to align the label when used with large inline Blueprint controls.

@css form-group

@## JavaScript API

The `FormGroup` component is available in the __@blueprintjs/core__ package.
Make sure to review the [getting started docs for installation info](#blueprint/getting-started).

This component is a simple wrapper around the CSS API that abstracts away the HTML complexity.

```tsx
<FormGroup
helperText="Helper text with details..."
label="Label A"
labelFor="text-input"
requiredLabel={true}
>
<input id="text-input" placeholder="Placeholder text" />
</FormGroup>
```

@interface IFormGroupProps
6 changes: 3 additions & 3 deletions packages/core/src/components/forms/formGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ export class FormGroup extends React.PureComponent<IFormGroupProps, {}> {
*
* Defaults to `<span class={Classes.TEXT_MUTED}>(required)</span>`.
*/
public static DEFAULT_REQUIRED_CONTENT = <span className={Classes.TEXT_MUTED}>(required)</span>;
public static DEFAULT_REQUIRED_CONTENT = <span className={Classes.TEXT_MUTED}> (required)</span>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't fix the issue if the user supplies their own required label. instead add {" "} in the JSX itself between the two elements (at the end of line 64).


public render() {
const { children, label, labelFor } = this.props;
return (
<div className={this.getClassName()}>
<label className={Classes.LABEL} htmlFor={labelFor}>
{label}
<span className={Classes.LABEL_TEXT}>{label}</span>
{this.maybeRenderRequiredLabel()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to add a space between the two elements here, or via margin in CSS. {label}{" "}{this...}

</label>
<div className={Classes.FORM_CONTENT}>
Expand All @@ -87,7 +87,7 @@ export class FormGroup extends React.PureComponent<IFormGroupProps, {}> {

private maybeRenderRequiredLabel() {
const { requiredLabel } = this.props;
return requiredLabel === true ? FormGroup.DEFAULT_REQUIRED_CONTENT : requiredLabel;
return requiredLabel === true ? FormGroup.DEFAULT_REQUIRED_CONTENT : <span> {requiredLabel}</span>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above

}

private maybeRenderHelperText() {
Expand Down
39 changes: 21 additions & 18 deletions packages/core/src/components/forms/label.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
@# Labels

Labels enhance the usability of your forms.

<div class="@ns-callout @ns-intent-success @ns-icon-comparison">
<h4 class="@ns-callout-title">Simple labels vs. form groups</h4>
<p>Blueprint provides two ways of connecting label text to control fields, depending on the complexity of the control.</p>
<p>Simple labels are a basic way to connect a label with a single control.</p>
<p>Form groups support more complex control layouts but require more markup to maintain consistent visuals.</p>
</div>

Labels enhance the usability of your forms.

@reactExample LabelExample

@## JavaScript API
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again with the moving JS before CSS


The `Label` component is available in the __@blueprintjs/core__ package. Make sure to review the [getting started docs for installation info](#blueprint/getting-started).

This component is a simple wrapper around the corresponding CSS API. It supports the full range of HTML props.

```tsx
<Label
helperText="Helper text with details..."
text="Label A"
>
<input className="@ns-input" id="text-input" placeholder="Placeholder text" />
</Label>
```

@interface ILabelProps

@## CSS API

@### Simple labels
Expand All @@ -33,19 +52,3 @@ must add the `:disabled` attribute directly to any nested elements to disable th

@css label-disabled

@## JavaScript API

The `Label` component is available in the __@blueprintjs/core__ package. Make sure to review the [getting started docs for installation info](#blueprint/getting-started).

This component is a simple wrapper around the corresponding CSS API. It supports the full range of HTML props.

```tsx
<Label
helperText="Helper text with details..."
text="Label A"
>
<input className="@ns-input" id="text-input" placeholder="Placeholder text" />
</Label>
```

@interface ILabelProps
2 changes: 1 addition & 1 deletion packages/core/src/components/forms/label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Label extends React.PureComponent<ILabelProps, {}> {

return (
<label {...htmlProps} className={rootClasses}>
{text}
<span className={Classes.LABEL_TEXT}>{text}</span>
{helperText && <span className={Classes.TEXT_MUTED}> {helperText}</span>}
{children}
</label>
Expand Down
62 changes: 62 additions & 0 deletions packages/docs-app/src/examples/core-examples/formGroupExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2016 Palantir Technologies, Inc. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2018

*
* Licensed under the terms of the LICENSE file distributed with this project.
*/

import * as React from "react";

import { FormGroup, InputGroup, Switch } from "@blueprintjs/core";
import { BaseExample, handleBooleanChange } from "@blueprintjs/docs-theme";

export interface IFormGroupExampleState {
disabled: boolean;
helperText: boolean;
inline: boolean;
}

export class FormGroupExample extends BaseExample<IFormGroupExampleState> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rewrite for new example syntax

public state: IFormGroupExampleState = {
disabled: false,
helperText: false,
inline: false,
};

protected className = "docs-label-example";

private handleDisabledChange = handleBooleanChange(disabled => this.setState({ disabled }));
private handleHelperTextChange = handleBooleanChange(helperText => this.setState({ helperText }));
private handleInlineChange = handleBooleanChange(inline => this.setState({ inline }));

protected renderExample() {
const { disabled, helperText, inline } = this.state;
return (
<FormGroup
disabled={disabled}
helperText={helperText ? "Helper text with details..." : undefined}
inline={inline}
label="Label"
requiredLabel={true}
labelFor="text-input"
>
<InputGroup id="text-input" placeholder="Placeholder text" disabled={disabled} />
</FormGroup>
);
}

protected renderOptions() {
const { disabled, helperText, inline } = this.state;
return [
[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fragment!!!

<Switch key="inline" label="Inline" checked={inline} onChange={this.handleInlineChange} />,
<Switch
key="helperText"
label="Show helper text"
checked={helperText}
onChange={this.handleHelperTextChange}
/>,
<Switch key="disabled" label="Disabled" checked={disabled} onChange={this.handleDisabledChange} />,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put this switch first please (alph)

],
];
}
}
2 changes: 2 additions & 0 deletions packages/docs-app/src/examples/core-examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ export * from "./contextMenuExample";
export * from "./dropdownMenuExample";
export * from "./editableTextExample";
export * from "./focusExample";
export * from "./formGroupExample";
export * from "./hotkeyPiano";
export * from "./hotkeyTester";
export * from "./iconExample";
export * from "./labelExample";
export * from "./menuExample";
export * from "./navbarExample";
export * from "./numericInputBasicExample";
Expand Down
61 changes: 61 additions & 0 deletions packages/docs-app/src/examples/core-examples/labelExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2016 Palantir Technologies, Inc. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2018

*
* Licensed under the terms of the LICENSE file distributed with this project.
*/

import * as React from "react";

import { InputGroup, Label, Switch } from "@blueprintjs/core";
import { BaseExample, handleBooleanChange } from "@blueprintjs/docs-theme";

export interface ILabelExampleState {
disabled: boolean;
helperText: boolean;
inline: boolean;
}

export class LabelExample extends BaseExample<ILabelExampleState> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given #2460, do we really want to add a Label example if we're gonna kill it for FormGroup soon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it doesn't hurt to have one for now, helps with testing and comparing with FormGroup. will be easy enough to remove it if we really kill Label

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rewrite to use new Example component

public state: ILabelExampleState = {
disabled: false,
helperText: false,
inline: false,
};

protected className = "docs-label-example";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are not necessary. let's only add them when required for custom styles


private handleDisabledChange = handleBooleanChange(disabled => this.setState({ disabled }));
private handleHelperTextChange = handleBooleanChange(helperText => this.setState({ helperText }));
private handleInlineChange = handleBooleanChange(inline => this.setState({ inline }));

protected renderExample() {
const { disabled, helperText, inline, ...labelProps } = this.state;
return (
<Label
disabled={disabled}
helperText={helperText ? "(required)" : undefined}
inline={inline}
text="Label"
{...labelProps}
>
<InputGroup type="text" placeholder="Input with icon" leftIcon="text-highlight" disabled={disabled} />
</Label>
);
}

protected renderOptions() {
const { disabled, helperText, inline } = this.state;
return [
[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fragment!!!

<Switch key="inline" label="Inline" checked={inline} onChange={this.handleInlineChange} />,
<Switch
key="helperText"
label="Show helper text"
checked={helperText}
onChange={this.handleHelperTextChange}
/>,
<Switch key="disabled" label="Disabled" checked={disabled} onChange={this.handleDisabledChange} />,
],
];
}
}