kopia lustrzana https://github.com/shoelace-style/shoelace
				
				
				
			Add support for link buttons; closes #165
							rodzic
							
								
									883d6974e9
								
							
						
					
					
						commit
						12581ca76b
					
				| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
## 2.0.0-beta.12
 | 
			
		||||
 | 
			
		||||
- Added support for `href`, `target`, and `download` to buttons
 | 
			
		||||
- Fixed a bug where buttons would have horizontal spacing in Safari
 | 
			
		||||
- Fixed a bug that caused an import resolution error when using Shoelace in a Stencil app
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,6 +63,19 @@ Use the `text` type to create text buttons that share the same size as regular b
 | 
			
		|||
<sl-button type="text" size="large">Text</sl-button>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Link Buttons
 | 
			
		||||
 | 
			
		||||
It's often helpful to have a button that works like a link. This is possible by setting the `href` attribute, which will make the component render an `<a>` under the hood. This gives you all the default link behavior the browser provides (e.g. <kbd>CMD/CTRL/SHIFT + CLICK</kbd>) and exposes the `target` and `download` attributes.
 | 
			
		||||
 | 
			
		||||
```html preview
 | 
			
		||||
<sl-button href="https://example.com/">Link</sl-button>
 | 
			
		||||
<sl-button href="https://example.com/" target="_blank">New Window</sl-button>
 | 
			
		||||
<sl-button href="/assets/images/wordmark.svg" download="shoelace.svg">Download</sl-button>
 | 
			
		||||
<sl-button href="https://example.com/" disabled>Disabled</sl-button>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
?> When a `target` is set, the link will receive `rel="noreferrer noopener"` for [security reasons](https://mathiasbynens.github.io/rel-noopener/).
 | 
			
		||||
 | 
			
		||||
### Setting a Custom Width
 | 
			
		||||
 | 
			
		||||
As expected, buttons can be given a custom width by setting its `width`. This is useful for making buttons span the full width of their container on smaller screens.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,12 +73,20 @@ export namespace Components {
 | 
			
		|||
          * Set to true to disable the button.
 | 
			
		||||
         */
 | 
			
		||||
        "disabled": boolean;
 | 
			
		||||
        /**
 | 
			
		||||
          * Tells the browser to download the linked file as this filename. Only used when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "download": string;
 | 
			
		||||
        /**
 | 
			
		||||
          * When set, the underlying button will be rendered as an `<a>` with this `href` instead of a `<button>`.
 | 
			
		||||
         */
 | 
			
		||||
        "href": string;
 | 
			
		||||
        /**
 | 
			
		||||
          * Set to true to draw the button in a loading state.
 | 
			
		||||
         */
 | 
			
		||||
        "loading": boolean;
 | 
			
		||||
        /**
 | 
			
		||||
          * An optional name for the button.
 | 
			
		||||
          * An optional name for the button. Ignored when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "name": string;
 | 
			
		||||
        /**
 | 
			
		||||
| 
						 | 
				
			
			@ -98,15 +106,19 @@ export namespace Components {
 | 
			
		|||
         */
 | 
			
		||||
        "size": 'small' | 'medium' | 'large';
 | 
			
		||||
        /**
 | 
			
		||||
          * Indicates if activating the button should submit the form.
 | 
			
		||||
          * Indicates if activating the button should submit the form. Ignored when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "submit": boolean;
 | 
			
		||||
        /**
 | 
			
		||||
          * Tells the browser where to open the link. Only used when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "target": '_blank' | '_parent' | '_self' | '_top';
 | 
			
		||||
        /**
 | 
			
		||||
          * The button's type.
 | 
			
		||||
         */
 | 
			
		||||
        "type": 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text';
 | 
			
		||||
        /**
 | 
			
		||||
          * An optional value for the button.
 | 
			
		||||
          * An optional value for the button. Ignored when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "value": string;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1236,12 +1248,20 @@ declare namespace LocalJSX {
 | 
			
		|||
          * Set to true to disable the button.
 | 
			
		||||
         */
 | 
			
		||||
        "disabled"?: boolean;
 | 
			
		||||
        /**
 | 
			
		||||
          * Tells the browser to download the linked file as this filename. Only used when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "download"?: string;
 | 
			
		||||
        /**
 | 
			
		||||
          * When set, the underlying button will be rendered as an `<a>` with this `href` instead of a `<button>`.
 | 
			
		||||
         */
 | 
			
		||||
        "href"?: string;
 | 
			
		||||
        /**
 | 
			
		||||
          * Set to true to draw the button in a loading state.
 | 
			
		||||
         */
 | 
			
		||||
        "loading"?: boolean;
 | 
			
		||||
        /**
 | 
			
		||||
          * An optional name for the button.
 | 
			
		||||
          * An optional name for the button. Ignored when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "name"?: string;
 | 
			
		||||
        /**
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,15 +1281,19 @@ declare namespace LocalJSX {
 | 
			
		|||
         */
 | 
			
		||||
        "size"?: 'small' | 'medium' | 'large';
 | 
			
		||||
        /**
 | 
			
		||||
          * Indicates if activating the button should submit the form.
 | 
			
		||||
          * Indicates if activating the button should submit the form. Ignored when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "submit"?: boolean;
 | 
			
		||||
        /**
 | 
			
		||||
          * Tells the browser where to open the link. Only used when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "target"?: '_blank' | '_parent' | '_self' | '_top';
 | 
			
		||||
        /**
 | 
			
		||||
          * The button's type.
 | 
			
		||||
         */
 | 
			
		||||
        "type"?: 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text';
 | 
			
		||||
        /**
 | 
			
		||||
          * An optional value for the button.
 | 
			
		||||
          * An optional value for the button. Ignored when `href` is set.
 | 
			
		||||
         */
 | 
			
		||||
        "value"?: string;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
  border-width: var(--sl-input-border-width);
 | 
			
		||||
  font-family: var(--sl-input-font-family);
 | 
			
		||||
  font-weight: var(--sl-font-weight-semibold);
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,13 +75,13 @@
 | 
			
		|||
    border-color: var(--sl-color-gray-80);
 | 
			
		||||
    color: var(--sl-color-gray-40);
 | 
			
		||||
 | 
			
		||||
    &:hover:not(:disabled) {
 | 
			
		||||
    &:hover:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-primary-95);
 | 
			
		||||
      border-color: var(--sl-color-primary-80);
 | 
			
		||||
      color: var(--sl-color-primary-40);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:focus:not(:disabled) {
 | 
			
		||||
    &:focus:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-primary-95);
 | 
			
		||||
      border-color: var(--sl-color-primary-70);
 | 
			
		||||
      color: var(--sl-color-primary-40);
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +89,7 @@
 | 
			
		|||
        hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:active:not(:disabled) {
 | 
			
		||||
    &:active:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-primary-95);
 | 
			
		||||
      border-color: var(--sl-color-primary-50);
 | 
			
		||||
      color: var(--sl-color-primary-30);
 | 
			
		||||
| 
						 | 
				
			
			@ -100,13 +101,13 @@
 | 
			
		|||
    border-color: var(--sl-color-primary-50);
 | 
			
		||||
    color: var(--sl-color-primary-text);
 | 
			
		||||
 | 
			
		||||
    &:hover:not(:disabled) {
 | 
			
		||||
    &:hover:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-primary-60);
 | 
			
		||||
      border-color: var(--sl-color-primary-60);
 | 
			
		||||
      color: var(--sl-color-primary-text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:focus:not(:disabled) {
 | 
			
		||||
    &:focus:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-primary-60);
 | 
			
		||||
      border-color: var(--sl-color-primary-60);
 | 
			
		||||
      color: var(--sl-color-primary-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +115,7 @@
 | 
			
		|||
        hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:active:not(:disabled) {
 | 
			
		||||
    &:active:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-primary-50);
 | 
			
		||||
      border-color: var(--sl-color-primary-50);
 | 
			
		||||
      color: var(--sl-color-primary-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -126,13 +127,13 @@
 | 
			
		|||
    border-color: var(--sl-color-success-50);
 | 
			
		||||
    color: var(--sl-color-success-text);
 | 
			
		||||
 | 
			
		||||
    &:hover:not(:disabled) {
 | 
			
		||||
    &:hover:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-success-60);
 | 
			
		||||
      border-color: var(--sl-color-success-60);
 | 
			
		||||
      color: var(--sl-color-success-text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:focus:not(:disabled) {
 | 
			
		||||
    &:focus:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-success-60);
 | 
			
		||||
      border-color: var(--sl-color-success-60);
 | 
			
		||||
      color: var(--sl-color-success-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +141,7 @@
 | 
			
		|||
        hsla(var(--sl-color-success-hue), var(--sl-color-success-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:active:not(:disabled) {
 | 
			
		||||
    &:active:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-success-50);
 | 
			
		||||
      border-color: var(--sl-color-success-50);
 | 
			
		||||
      color: var(--sl-color-success-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -152,13 +153,13 @@
 | 
			
		|||
    border-color: var(--sl-color-info-50);
 | 
			
		||||
    color: var(--sl-color-info-text);
 | 
			
		||||
 | 
			
		||||
    &:hover:not(:disabled) {
 | 
			
		||||
    &:hover:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-info-60);
 | 
			
		||||
      border-color: var(--sl-color-info-60);
 | 
			
		||||
      color: var(--sl-color-info-text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:focus:not(:disabled) {
 | 
			
		||||
    &:focus:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-info-60);
 | 
			
		||||
      border-color: var(--sl-color-info-60);
 | 
			
		||||
      color: var(--sl-color-info-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +167,7 @@
 | 
			
		|||
        hsla(var(--sl-color-info-hue), var(--sl-color-info-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:active:not(:disabled) {
 | 
			
		||||
    &:active:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-info-50);
 | 
			
		||||
      border-color: var(--sl-color-info-50);
 | 
			
		||||
      color: var(--sl-color-info-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -178,13 +179,13 @@
 | 
			
		|||
    border-color: var(--sl-color-warning-50);
 | 
			
		||||
    color: var(--sl-color-warning-text);
 | 
			
		||||
 | 
			
		||||
    &:hover:not(:disabled) {
 | 
			
		||||
    &:hover:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-warning-60);
 | 
			
		||||
      border-color: var(--sl-color-warning-60);
 | 
			
		||||
      color: var(--sl-color-warning-text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:focus:not(:disabled) {
 | 
			
		||||
    &:focus:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-warning-60);
 | 
			
		||||
      border-color: var(--sl-color-warning-60);
 | 
			
		||||
      color: var(--sl-color-warning-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +193,7 @@
 | 
			
		|||
        hsla(var(--sl-color-warning-hue), var(--sl-color-warning-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:active:not(:disabled) {
 | 
			
		||||
    &:active:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-warning-50);
 | 
			
		||||
      border-color: var(--sl-color-warning-50);
 | 
			
		||||
      color: var(--sl-color-warning-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -204,13 +205,13 @@
 | 
			
		|||
    border-color: var(--sl-color-danger-50);
 | 
			
		||||
    color: var(--sl-color-danger-text);
 | 
			
		||||
 | 
			
		||||
    &:hover:not(:disabled) {
 | 
			
		||||
    &:hover:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-danger-60);
 | 
			
		||||
      border-color: var(--sl-color-danger-60);
 | 
			
		||||
      color: var(--sl-color-danger-text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:focus:not(:disabled) {
 | 
			
		||||
    &:focus:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-danger-60);
 | 
			
		||||
      border-color: var(--sl-color-danger-60);
 | 
			
		||||
      color: var(--sl-color-danger-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +219,7 @@
 | 
			
		|||
        hsla(var(--sl-color-danger-hue), var(--sl-color-danger-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:active:not(:disabled) {
 | 
			
		||||
    &:active:not(.button--disabled) {
 | 
			
		||||
      background-color: var(--sl-color-danger-50);
 | 
			
		||||
      border-color: var(--sl-color-danger-50);
 | 
			
		||||
      color: var(--sl-color-danger-text);
 | 
			
		||||
| 
						 | 
				
			
			@ -235,13 +236,13 @@
 | 
			
		|||
  border-color: transparent;
 | 
			
		||||
  color: var(--sl-color-primary-50);
 | 
			
		||||
 | 
			
		||||
  &:hover:not(:disabled) {
 | 
			
		||||
  &:hover:not(.button--disabled) {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    border-color: transparent;
 | 
			
		||||
    color: var(--sl-color-primary-60);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:focus:not(:disabled) {
 | 
			
		||||
  &:focus:not(.button--disabled) {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    border-color: transparent;
 | 
			
		||||
    color: var(--sl-color-primary-60);
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +250,7 @@
 | 
			
		|||
      hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:active:not(:disabled) {
 | 
			
		||||
  &:active:not(.button--disabled) {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    border-color: transparent;
 | 
			
		||||
    color: var(--sl-color-primary-40);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,20 +40,29 @@ export class Button {
 | 
			
		|||
  /** Set to true to draw the button in a loading state. */
 | 
			
		||||
  @Prop() loading = false;
 | 
			
		||||
 | 
			
		||||
  /** An optional name for the button. */
 | 
			
		||||
  @Prop() name: string;
 | 
			
		||||
 | 
			
		||||
  /** Set to true to draw a pill-style button with rounded edges. */
 | 
			
		||||
  @Prop() pill = false;
 | 
			
		||||
 | 
			
		||||
  /** Set to true to draw a circle button. */
 | 
			
		||||
  @Prop() circle = false;
 | 
			
		||||
 | 
			
		||||
  /** An optional value for the button. */
 | 
			
		||||
  /** Indicates if activating the button should submit the form. Ignored when `href` is set. */
 | 
			
		||||
  @Prop() submit = false;
 | 
			
		||||
 | 
			
		||||
  /** An optional name for the button. Ignored when `href` is set. */
 | 
			
		||||
  @Prop() name: string;
 | 
			
		||||
 | 
			
		||||
  /** An optional value for the button. Ignored when `href` is set. */
 | 
			
		||||
  @Prop() value: string;
 | 
			
		||||
 | 
			
		||||
  /** Indicates if activating the button should submit the form. */
 | 
			
		||||
  @Prop() submit = false;
 | 
			
		||||
  /** When set, the underlying button will be rendered as an `<a>` with this `href` instead of a `<button>`. */
 | 
			
		||||
  @Prop() href: string;
 | 
			
		||||
 | 
			
		||||
  /** Tells the browser where to open the link. Only used when `href` is set. */
 | 
			
		||||
  @Prop() target: '_blank' | '_parent' | '_self' | '_top';
 | 
			
		||||
 | 
			
		||||
  /** Tells the browser to download the linked file as this filename. Only used when `href` is set. */
 | 
			
		||||
  @Prop() download: string;
 | 
			
		||||
 | 
			
		||||
  /** Emitted when the button loses focus. */
 | 
			
		||||
  @Event() slBlur: EventEmitter;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +106,12 @@ export class Button {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const isLink = this.href ? true : false;
 | 
			
		||||
    const isButton = !isLink;
 | 
			
		||||
    const Button = isLink ? 'a' : 'button';
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <button
 | 
			
		||||
      <Button
 | 
			
		||||
        ref={el => (this.button = el)}
 | 
			
		||||
        part="base"
 | 
			
		||||
        class={{
 | 
			
		||||
| 
						 | 
				
			
			@ -126,10 +139,14 @@ export class Button {
 | 
			
		|||
          'button--loading': this.loading,
 | 
			
		||||
          'button--pill': this.pill
 | 
			
		||||
        }}
 | 
			
		||||
        name={this.name}
 | 
			
		||||
        value={this.value}
 | 
			
		||||
        disabled={this.disabled}
 | 
			
		||||
        type={this.submit ? 'submit' : 'button'}
 | 
			
		||||
        type={isButton && this.submit ? 'submit' : 'button'}
 | 
			
		||||
        name={isButton ? this.name : null}
 | 
			
		||||
        value={isButton ? this.value : null}
 | 
			
		||||
        href={isLink && this.href}
 | 
			
		||||
        target={isLink && this.target ? this.target : null}
 | 
			
		||||
        download={isLink && this.download ? this.download : null}
 | 
			
		||||
        rel={isLink && this.target ? 'noreferrer noopener' : null}
 | 
			
		||||
        onBlur={this.handleBlur}
 | 
			
		||||
        onFocus={this.handleFocus}
 | 
			
		||||
        onClick={this.handleClick}
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +176,7 @@ export class Button {
 | 
			
		|||
        )}
 | 
			
		||||
 | 
			
		||||
        {this.loading && <sl-spinner />}
 | 
			
		||||
      </button>
 | 
			
		||||
      </Button>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue